sandal 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/sandal.rb CHANGED
@@ -11,37 +11,49 @@ require 'sandal/enc'
11
11
  # A library for creating and reading JSON Web Tokens (JWT).
12
12
  module Sandal
13
13
 
14
- # Creates a signed token.
15
- def self.encode_token(payload, sig, header_fields = nil)
14
+ # Creates a signed JSON Web Token.
15
+ #
16
+ # @param payload [String] The payload of the token.
17
+ # @param signer [Sandal::Sig] The token signer, which may be nil for an unsigned token.
18
+ # @param header_fields [Hash] Header fields for the token (note: do not include 'alg').
19
+ # @return [String] A signed JSON Web Token.
20
+ def self.encode_token(payload, signer, header_fields = nil)
16
21
  if header_fields && header_fields['enc']
17
22
  throw ArgumentError.new('The header cannot contain an "enc" parameter.')
18
23
  end
19
- sig ||= Sandal::Sig::None.instance
24
+ signer ||= Sandal::Sig::None.instance
20
25
 
21
26
  header = {}
22
- header['alg'] = sig.name if sig.name != Sandal::Sig::None.instance.name
27
+ header['alg'] = signer.name if signer.name != Sandal::Sig::None.instance.name
23
28
  header = header_fields.merge(header) if header_fields
24
29
 
25
30
  encoded_header = Sandal::Util.base64_encode(JSON.generate(header))
26
31
  encoded_payload = Sandal::Util.base64_encode(payload)
27
32
  secured_input = [encoded_header, encoded_payload].join('.')
28
33
 
29
- signature = sig.sign(secured_input)
34
+ signature = signer.sign(secured_input)
30
35
  encoded_signature = Sandal::Util.base64_encode(signature)
31
36
  [secured_input, encoded_signature].join('.')
32
37
  end
33
38
 
34
- # Creates an encrypted token.
35
- def self.encrypt_token(payload, enc, header_fields = nil)
39
+ # Creates an encrypted JSON Web Token.
40
+ #
41
+ # @param payload [String] The payload of the token.
42
+ # @param encrypted [Sandal::Enc] The token encrypter.
43
+ # @param header_fields [Hash] Header fields for the token (note: do not include 'alg' or 'enc').
44
+ # @return [String] An encrypted JSON Web Token.
45
+ def self.encrypt_token(payload, encrypter, header_fields = nil)
36
46
  header = {}
37
- header['enc'] = enc.name
38
- header['alg'] = enc.alg_name
47
+ header['enc'] = encrypter.name
48
+ header['alg'] = encrypter.alg_name
39
49
  header = header_fields.merge(header) if header_fields
40
50
 
41
- enc.encrypt(header, payload)
51
+ encrypter.encrypt(header, payload)
42
52
  end
43
53
 
44
- # Decodes a token, verifying the signature if present.
54
+ # Decodes a JSON Web Token, verifying the signature as necessary.
55
+ #
56
+ # **NOTE: This method is likely to change, to allow more validation options**
45
57
  def self.decode_token(token, &sig_finder)
46
58
  parts = token.split('.')
47
59
  throw ArgumentError.new('Invalid token format.') unless [2, 3].include?(parts.length)
@@ -65,7 +77,9 @@ module Sandal
65
77
  payload
66
78
  end
67
79
 
68
- # Decrypts a token.
80
+ # Decrypts an encrypted JSON Web Token.
81
+ #
82
+ # **NOTE: This method is likely to change, to allow more validation options**
69
83
  def self.decrypt_token(encrypted_token, &enc_finder)
70
84
  parts = encrypted_token.split('.')
71
85
  throw ArgumentError.new('Invalid token format.') unless parts.length == 5
data/lib/sandal/sig.rb CHANGED
@@ -4,15 +4,22 @@ module Sandal
4
4
  # Common signature traits.
5
5
  module Sig
6
6
 
7
- # The JWA name of the algorithm.
7
+ # @return [String] The JWA name of the algorithm.
8
8
  attr_reader :name
9
9
 
10
10
  # Signs a payload and returns the signature.
11
+ #
12
+ # @param payload [String] The payload of the token to sign.
13
+ # @return [String] The signature.
11
14
  def sign(payload)
12
15
  throw NotImplementedError.new("#{@name}.sign is not implemented.")
13
16
  end
14
17
 
15
18
  # Verifies a payload signature and returns whether the signature matches.
19
+ #
20
+ # @param signature [String] The signature to verify.
21
+ # @param payload [String] The payload of the token.
22
+ # @return [Boolean] true if the signature is correct; otherwise false.
16
23
  def verify(signature, payload)
17
24
  throw NotImplementedError.new("#{@name}.verify is not implemented.")
18
25
  end
@@ -28,11 +35,18 @@ module Sandal
28
35
  end
29
36
 
30
37
  # Returns an empty signature.
38
+ #
39
+ # @param payload [String] This parameter is ignored.
40
+ # @return [String] An empty string.
31
41
  def sign(payload)
32
42
  ''
33
43
  end
34
44
 
35
- # Verifies that the signature is empty.
45
+ # Verifies that a signature is nil or empty.
46
+ #
47
+ # @param signature [String] The signature to verify.
48
+ # @param payload [String] This parameter is ignored.
49
+ # @return [Boolean] `true` if the signature is nil or empty; otherwise `false`.
36
50
  def verify(signature, payload)
37
51
  signature.nil? || signature.length == 0
38
52
  end
data/lib/sandal/sig/es.rb CHANGED
@@ -8,10 +8,11 @@ module Sandal
8
8
  include Sandal::Sig
9
9
 
10
10
  # Creates a new instance with the size of the SHA algorithm and an OpenSSL ES PKey.
11
- def initialize(sha_size, key)
11
+ def initialize(sha_size, prime_size, key)
12
12
  throw ArgumentError.new('A key is required.') unless key
13
13
  @name = "ES#{sha_size}"
14
14
  @digest = OpenSSL::Digest.new("sha#{sha_size}")
15
+ @prime_size = prime_size
15
16
  @key = key
16
17
  end
17
18
 
@@ -20,7 +21,7 @@ module Sandal
20
21
  hash = @digest.digest(payload)
21
22
  asn1_sig = @key.dsa_sign_asn1(hash)
22
23
  r, s = self.class.decode_asn1_signature(asn1_sig)
23
- self.class.encode_jws_signature(r, s)
24
+ self.class.encode_jws_signature(r, s, @prime_size)
24
25
  end
25
26
 
26
27
  # Verifies a payload signature and returns whether the signature matches.
@@ -45,22 +46,18 @@ module Sandal
45
46
 
46
47
  # Decodes a JWS signature into a pair of BNs.
47
48
  def self.decode_jws_signature(signature)
48
- binary_string = Sandal::Util.base64_decode(signature)
49
- coord_length = binary_string.length / 2
50
- r = OpenSSL::BN.new(binary_string[0..(coord_length - 1)].unpack('H*')[0], 16)
51
- s = OpenSSL::BN.new(binary_string[coord_length..-1].unpack('H*')[0], 16)
49
+ n_length = signature.length / 2
50
+ s_to_n = lambda { |s| OpenSSL::BN.new(s.unpack('H*')[0], 16) }
51
+ r = s_to_n.call(signature[0..(n_length - 1)])
52
+ s = s_to_n.call(signature[n_length..-1])
52
53
  return r, s
53
54
  end
54
55
 
55
56
  # Encodes a pair of BNs into a JWS signature.
56
- def self.encode_jws_signature(r, s)
57
- # TODO: Is there a better way to convert these to a binary string?
58
- r_str = [r.to_s(16)].pack('H*')
59
- r_str = "\x00" + r_str if r_str.length % 2 != 0
60
- s_str = [s.to_s(16)].pack('H*')
61
- s_str = "\x00" + s_str if s_str.length % 2 != 0
62
- binary_string = r_str + s_str
63
- Sandal::Util.base64_encode(binary_string)
57
+ def self.encode_jws_signature(r, s, prime_size)
58
+ byte_count = (prime_size / 8.0).ceil
59
+ n_to_s = lambda { |n| [n.to_s(16)].pack('H*').rjust(byte_count, "\0") }
60
+ n_to_s.call(r) + n_to_s.call(s)
64
61
  end
65
62
 
66
63
  end
@@ -69,7 +66,7 @@ module Sandal
69
66
  class ES256 < Sandal::Sig::ES
70
67
  # Creates a new instance with an OpenSSL ES PKey.
71
68
  def initialize(key)
72
- super(256, key)
69
+ super(256, 256, key)
73
70
  end
74
71
  end
75
72
 
@@ -77,7 +74,7 @@ module Sandal
77
74
  class ES384 < Sandal::Sig::ES
78
75
  # Creates a new instance with an OpenSSL ES PKey.
79
76
  def initialize(key)
80
- super(384, key)
77
+ super(384, 384, key)
81
78
  end
82
79
  end
83
80
 
@@ -85,7 +82,7 @@ module Sandal
85
82
  class ES512 < Sandal::Sig::ES
86
83
  # Creates a new instance with an OpenSSL ES PKey.
87
84
  def initialize(key)
88
- super(512, key)
85
+ super(512, 521, key)
89
86
  end
90
87
  end
91
88
 
@@ -1,4 +1,4 @@
1
1
  module Sandal
2
2
  # The semantic version of the library.
3
- VERSION = '0.0.2'
3
+ VERSION = '0.0.3'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sandal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-26 00:00:00.000000000 Z
12
+ date: 2013-03-29 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A ruby library for creating and reading JSON Web Tokens (JWT), supporting
15
15
  JSON Web Signatures (JWS) and JSON Web Encryption (JWE).
@@ -55,3 +55,4 @@ signing_key:
55
55
  specification_version: 3
56
56
  summary: A JSON Web Token (JWT) library.
57
57
  test_files: []
58
+ has_rdoc: