Class: Saro::Dat::DatSignatureKey

Inherits:
Object
  • Object
show all
Defined in:
lib/saro/dat/signature.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(algorithm, signing_key, verifying_key, config = nil) ⇒ DatSignatureKey

Returns a new instance of DatSignatureKey.



45
46
47
48
49
50
# File 'lib/saro/dat/signature.rb', line 45

def initialize(algorithm, signing_key, verifying_key, config = nil)
  @algorithm = algorithm
  @signing_key = signing_key
  @verifying_key = verifying_key
  @config = config || Saro::Dat.get_signature_config(algorithm)
end

Instance Attribute Details

#algorithmObject (readonly)

Returns the value of attribute algorithm.



43
44
45
# File 'lib/saro/dat/signature.rb', line 43

def algorithm
  @algorithm
end

#signing_keyObject (readonly)

Returns the value of attribute signing_key.



43
44
45
# File 'lib/saro/dat/signature.rb', line 43

def signing_key
  @signing_key
end

#verifying_keyObject (readonly)

Returns the value of attribute verifying_key.



43
44
45
# File 'lib/saro/dat/signature.rb', line 43

def verifying_key
  @verifying_key
end

Class Method Details

.generate(algorithm) ⇒ Object



93
94
95
96
97
# File 'lib/saro/dat/signature.rb', line 93

def self.generate(algorithm)
  config = Saro::Dat.get_signature_config(algorithm)
  key = OpenSSL::PKey::EC.generate(config[:curve])
  new(algorithm, key, key, config)
end

.imports(algorithm, format_str) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/saro/dat/signature.rb', line 99

def self.imports(algorithm, format_str)
  config = Saro::Dat.get_signature_config(algorithm)
  parts = format_str.split("~", -1)
  
  unless (1..2).cover?(parts.length)
    raise ArgumentError, "Invalid DAT Signature Key Format: No keys found"
  end

  signing_key = nil
  verifying_key = nil

  if parts[0] && !parts[0].empty?
    d_bytes = Saro::Dat::Util.decode_base64_url(parts[0])
    d_value = OpenSSL::BN.new(d_bytes, 2)
    
    # Handle public key if provided in parts[1] for signing key as well
    v_octet = if parts.length == 2 && parts[1] && !parts[1].empty?
                Saro::Dat::Util.decode_base64_url(parts[1])
              end

    signing_key = create_ec_key(config[:curve], d_value, v_octet)
    verifying_key = signing_key
  end

  if parts.length == 2 && parts[1] && !parts[1].empty?
    unless signing_key
      public_bytes = Saro::Dat::Util.decode_base64_url(parts[1])
      verifying_key = create_ec_key(config[:curve], nil, public_bytes)
    end
  elsif !signing_key
    raise ArgumentError, "Invalid DAT Signature Key Format: No keys found"
  end

  new(algorithm, signing_key, verifying_key, config)
end

Instance Method Details

#exports(option) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/saro/dat/signature.rb', line 135

def exports(option)
  rv_parts = ["", ""]

  if [DatSignatureKeyExportOption::PAIR, DatSignatureKeyExportOption::SIGNING].include?(option)
    if @signing_key&.private_key
      d_value = @signing_key.private_key
      # Ensure fixed length padding
      curve_size = (@signing_key.group.degree + 7) / 8
      d_bytes = d_value.to_s(2).rjust(curve_size, "\x00".b)
      rv_parts[0] = Saro::Dat::Util.encode_base64_url_str(d_bytes)
    elsif option == DatSignatureKeyExportOption::SIGNING
      raise ArgumentError, "Signature key is not supported - verifying only key"
    end
  end

  if [DatSignatureKeyExportOption::PAIR, DatSignatureKeyExportOption::VERIFYING].include?(option)
    # Uncompressed point: 0x04 + R + S
    public_bytes = @verifying_key.public_key.to_octet_string(:uncompressed)
    rv_parts[1] = Saro::Dat::Util.encode_base64_url_str(public_bytes)
  end

  case option
  when DatSignatureKeyExportOption::SIGNING
    rv_parts[0]
  when DatSignatureKeyExportOption::VERIFYING
    "~#{rv_parts[1]}"
  else
    "#{rv_parts[0]}~#{rv_parts[1]}"
  end
end

#has_signing_key?Boolean

Returns:

  • (Boolean)


196
197
198
# File 'lib/saro/dat/signature.rb', line 196

def has_signing_key?
  !@signing_key.nil?
end

#sign(body) ⇒ Object

Raises:

  • (ArgumentError)


166
167
168
169
170
171
172
173
174
175
# File 'lib/saro/dat/signature.rb', line 166

def sign(body)
  raise ArgumentError, "Signature key is not supported - verifying only key" unless @signing_key
  body = body.encode('utf-8') if body.is_a?(String) && body.encoding != Encoding::BINARY
  raise ArgumentError, "Sign Error - body is empty" if body.nil? || body.empty?

  digest = OpenSSL::Digest.new(@config[:hash])
  signature_der = @signing_key.dsa_sign_asn1(digest.digest(body))
  
  der_to_raw_signature(signature_der)
end

#verify(body, signature) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/saro/dat/signature.rb', line 177

def verify(body, signature)
  body = body.encode('utf-8') if body.is_a?(String) && body.encoding != Encoding::BINARY
  return false if body.nil? || body.empty?

  sig_bytes = if signature.is_a?(String) && signature.encoding != Encoding::BINARY
                Saro::Dat::Util.decode_base64_url(signature)
              else
                signature
              end

  begin
    der_sig = raw_to_der_signature(sig_bytes)
    digest = OpenSSL::Digest.new(@config[:hash])
    @verifying_key.dsa_verify_asn1(digest.digest(body), der_sig)
  rescue StandardError
    false
  end
end