Class: Sandal::Sig::ES
- Inherits:
-
Object
- Object
- Sandal::Sig::ES
- Defined in:
- lib/sandal/sig/es.rb
Overview
Base implementation of the ECDSA-SHA family of signature algorithms.
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
The JWA name of the algorithm.
Class Method Summary collapse
-
.decode_asn1_signature(signature) ⇒ OpenSSL::BN
Decodes an ASN.1 signature into a pair of BNs.
-
.decode_jws_signature(signature) ⇒ OpenSSL::BN
Decodes a JWS signature into a pair of BNs.
-
.encode_asn1_signature(r, s) ⇒ String
Encodes a pair of BNs into an ASN.1 signature.
-
.encode_jws_signature(r, s, prime_size) ⇒ String
Encodes a pair of BNs into a JWS signature.
Instance Method Summary collapse
-
#initialize(name, sha_size, prime_size, key) ⇒ ES
constructor
Creates a new instance; it’s probably easier to use one of the subclass constructors.
-
#sign(payload) ⇒ String
Signs a payload and returns the signature.
-
#valid?(signature, payload) ⇒ Boolean
Validates a payload signature and returns whether the signature matches.
Constructor Details
#initialize(name, sha_size, prime_size, key) ⇒ ES
Creates a new instance; it’s probably easier to use one of the subclass constructors.
19 20 21 22 23 24 |
# File 'lib/sandal/sig/es.rb', line 19 def initialize(name, sha_size, prime_size, key) @name = name @digest = OpenSSL::Digest.new("sha#{sha_size}") @prime_size = prime_size @key = key end |
Instance Attribute Details
#name ⇒ Object (readonly)
The JWA name of the algorithm.
10 11 12 |
# File 'lib/sandal/sig/es.rb', line 10 def name @name end |
Class Method Details
.decode_asn1_signature(signature) ⇒ OpenSSL::BN
Decodes an ASN.1 signature into a pair of BNs.
53 54 55 56 |
# File 'lib/sandal/sig/es.rb', line 53 def self.decode_asn1_signature(signature) asn_seq = OpenSSL::ASN1.decode(signature) return asn_seq.value[0].value, asn_seq.value[1].value end |
.decode_jws_signature(signature) ⇒ OpenSSL::BN
Decodes a JWS signature into a pair of BNs.
72 73 74 75 76 77 78 |
# File 'lib/sandal/sig/es.rb', line 72 def self.decode_jws_signature(signature) n_length = signature.length / 2 s_to_n = -> s { OpenSSL::BN.new(s.unpack("H*")[0], 16) } r = s_to_n.call(signature[0..(n_length - 1)]) s = s_to_n.call(signature[n_length..-1]) return r, s end |
.encode_asn1_signature(r, s) ⇒ String
Encodes a pair of BNs into an ASN.1 signature.
63 64 65 66 |
# File 'lib/sandal/sig/es.rb', line 63 def self.encode_asn1_signature(r, s) items = [OpenSSL::ASN1::Integer.new(r), OpenSSL::ASN1::Integer.new(s)] OpenSSL::ASN1::Sequence.new(items).to_der end |
.encode_jws_signature(r, s, prime_size) ⇒ String
Encodes a pair of BNs into a JWS signature.
86 87 88 89 90 |
# File 'lib/sandal/sig/es.rb', line 86 def self.encode_jws_signature(r, s, prime_size) byte_count = (prime_size / 8.0).ceil n_to_s = -> n { [n.to_s(16)].pack("H*").rjust(byte_count, "\0") } n_to_s.call(r) + n_to_s.call(s) end |
Instance Method Details
#sign(payload) ⇒ String
Signs a payload and returns the signature.
30 31 32 33 34 35 |
# File 'lib/sandal/sig/es.rb', line 30 def sign(payload) hash = @digest.digest(payload) asn1_sig = @key.dsa_sign_asn1(hash) r, s = self.class.decode_asn1_signature(asn1_sig) self.class.encode_jws_signature(r, s, @prime_size) end |
#valid?(signature, payload) ⇒ Boolean
Validates a payload signature and returns whether the signature matches.
42 43 44 45 46 47 |
# File 'lib/sandal/sig/es.rb', line 42 def valid?(signature, payload) hash = @digest.digest(payload) r, s = self.class.decode_jws_signature(signature) asn1_sig = self.class.encode_asn1_signature(r, s) @key.dsa_verify_asn1(hash, asn1_sig) end |