Sha256: 66fd6d6f2b5bef6c14738cfe1c4974c849c856d195c81492d677f17966551b92

Contents?: true

Size: 1.98 KB

Versions: 1

Compression:

Stored size: 1.98 KB

Contents

# frozen_string_literal: true

require "openssl"
require "openssl/signature_algorithm/base"

module OpenSSL
  module SignatureAlgorithm
    class ECDSA < Base
      BYTE_LENGTH = 8

      class SigningKey < OpenSSL::PKey::EC
        def initialize(*args)
          super(*args).generate_key
        end

        def verify_key
          VerifyKey.new(group, public_key.to_bn)
        end
      end

      class VerifyKey < OpenSSL::PKey::EC::Point
        def self.deserialize(pem_string)
          new(OpenSSL::PKey::EC.new(pem_string).public_key)
        end

        def serialize
          ec_key.to_pem
        end

        def ec_key
          @ec_key ||=
            begin
              ec_key = OpenSSL::PKey::EC.new(group)
              ec_key.public_key = self

              ec_key
            end
        end

        def verify(*args)
          ec_key.verify(*args)
        end
      end

      CURVE_BY_DIGEST_LENGTH = {
        "256" => "prime256v1",
        "384" => "secp384r1",
        "512" => "secp521r1"
      }.freeze

      def generate_signing_key
        @signing_key = SigningKey.new(curve_name)
      end

      def curve_name
        CURVE_BY_DIGEST_LENGTH[digest_length] ||
          raise(OpenSSL::SignatureAlgorithm::Error, "Unsupported digest length #{digest_length}")
      end

      private

      # Borrowed from jwt rubygem.
      # https://github.com/jwt/ruby-jwt/blob/7a6a3f1dbaff806993156d1dff9c217bb2523ff8/lib/jwt/security_utils.rb#L34-L39
      #
      # Hopefully this will be provided by openssl rubygem in the future.
      def formatted_signature(signature)
        n = (verify_key_length.to_f / BYTE_LENGTH).ceil

        if signature.size == n * 2
          r = signature[0..(n - 1)]
          s = signature[n..-1]

          OpenSSL::ASN1::Sequence.new([r, s].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
        else
          signature
        end
      end

      def verify_key_length
        verify_key.group.degree
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
openssl-signature_algorithm-0.4.0 lib/openssl/signature_algorithm/ecdsa.rb