sandal 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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: