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 +26 -12
- data/lib/sandal/sig.rb +16 -2
- data/lib/sandal/sig/es.rb +14 -17
- data/lib/sandal/version.rb +1 -1
- metadata +3 -2
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
|
15
|
-
|
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
|
-
|
24
|
+
signer ||= Sandal::Sig::None.instance
|
20
25
|
|
21
26
|
header = {}
|
22
|
-
header['alg'] =
|
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 =
|
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
|
35
|
-
|
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'] =
|
38
|
-
header['alg'] =
|
47
|
+
header['enc'] = encrypter.name
|
48
|
+
header['alg'] = encrypter.alg_name
|
39
49
|
header = header_fields.merge(header) if header_fields
|
40
50
|
|
41
|
-
|
51
|
+
encrypter.encrypt(header, payload)
|
42
52
|
end
|
43
53
|
|
44
|
-
# Decodes a
|
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
|
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
|
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
|
-
|
49
|
-
|
50
|
-
r =
|
51
|
-
s =
|
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
|
-
|
58
|
-
|
59
|
-
|
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
|
|
data/lib/sandal/version.rb
CHANGED
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.
|
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-
|
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:
|