class CryptoToolchain::BlackBoxes::RSAKeypair

Constants

PrivateKey
PublicKey

Attributes

bits[R]
e[R]
p[R]
q[R]

Public Class Methods

new(bits: 1024, p: nil, q: nil) click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 8
def initialize(bits: 1024, p: nil, q: nil)
  @bits = bits
  @p = p || OpenSSL::BN::generate_prime(bits/2).to_i
  @q = q || OpenSSL::BN::generate_prime(bits/2).to_i
  @n = @p * @q
  et = (@p-1) * (@q-1)
  @e = 3
  @d = @e.invmod(et)
end

Public Instance Methods

asn1(hash_type) click to toggle source

Values from stackoverflow.com/questions/3713774/c-sharp-how-to-calculate-asn-1-der-encoding-of-a-particular-hash-algorithm

# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 76
def asn1(hash_type)
  raise ArgumentError.new("Only sha1 is supported") unless hash_type == :sha1
  {
    md5:    "0 0\f\x06\b*\x86H\x86\xF7\r\x02\x05\x05\x00\x04\x10",
    sha1:   "0!0\t\x06\x05+\x0E\x03\x02\x1A\x05\x00\x04\x14",
    sha256: "010\r\x06\t`\x86H\x01e\x03\x04\x02\x01\x05\x00\x04 ",
    sha384: "0A0\r\x06\t`\x86H\x01e\x03\x04\x02\x02\x05\x00\x040",
    sha512: "0Q0\r\x06\t`\x86H\x01e\x03\x04\x02\x03\x05\x00\x04@"
  }.fetch(hash_type)
end
decrypt(m, pad: false) click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 28
def decrypt(m, pad: false)
  raise ArgumentError.new("Message should be a string") unless m.is_a?(String)
  decrypted = m.
                to_number.
                modpow(private_key.d, private_key.n).
                to_bin_string
  if pad
    pad_to_key_size(decrypted)
  else
    decrypted
  end
end
encrypt(m, to: ) click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 20
def encrypt(m, to: )
  raise ArgumentError.new("Message should be a string") unless m.is_a?(String)
  m.
    to_number.
    modpow(to.e, to.n).
    to_bin_string
end
pad_to_key_size(str) click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 87
def pad_to_key_size(str)
  padded = str.dup
  while padded.bytesize < bits / 8
    padded = "\x00#{padded}"
  end
  padded
end
private_key() click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 69
def private_key
  @private_key ||= PrivateKey.new(@d, @n)
end
Also aliased as: privkey
privkey()
Alias for: private_key
pubkey()
Alias for: public_key
public_key() click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 64
def public_key
  @public_key ||= PublicKey.new(@e, @n)
end
Also aliased as: pubkey
sign(plaintext) click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 41
def sign(plaintext)
  blocksize = bits / 8
  digest = CryptoToolchain::Utilities::SHA1.digest(plaintext)
  asn = asn1(:sha1)
  # the 4 is the mandatory 0x00 0x01 0xff 0x00
  pad_num = blocksize - ( digest.bytesize + asn.bytesize + 4)
  block = "\x00\x01\xff" + (0xff.chr * pad_num) + "\x00" + asn + digest
  decrypt(block)
end
verify(message, signature: , lazy: true) click to toggle source
# File lib/crypto_toolchain/black_boxes/rsa_keypair.rb, line 51
def verify(message, signature: , lazy: true)
  raise("I can't not be lazy") unless lazy
  enc = encrypt(signature, to: pubkey)
  asn = ASN1.fetch(:sha1)
  regex = /(?<padding>\x01\xff+\x00)(?<asn>.{#{asn.bytesize}})(?<hash>.{20})/m
  begin
    _padding, potential_asn, hash = enc.match(regex).captures
  rescue
    return false
  end
  potential_asn == asn && hash == CryptoToolchain::Utilities::SHA1.digest(message)
end