Class: Eth::OpenSsl
- Inherits:
-
Object
- Object
- Eth::OpenSsl
- Extended by:
- FFI::Library
- Defined in:
- lib/eth/open_ssl.rb
Constant Summary collapse
- NID_secp256k1 =
714
- POINT_CONVERSION_COMPRESSED =
2
- POINT_CONVERSION_UNCOMPRESSED =
4
- VERSION_1_1_0_NUM =
OpenSSL 1.1.0 version as a numerical version value as defined in: www.openssl.org/docs/man1.1.0/man3/OpenSSL_version.html
0x10100000
- OPENSSL_INIT_ENGINE_RDRAND =
OpenSSL 1.1.0 engine constants, taken from: github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h
0x00000200
- OPENSSL_INIT_ENGINE_DYNAMIC =
0x00000400
- OPENSSL_INIT_ENGINE_CRYPTODEV =
0x00001000
- OPENSSL_INIT_ENGINE_CAPI =
0x00002000
- OPENSSL_INIT_ENGINE_PADLOCK =
0x00004000
- OPENSSL_INIT_ENGINE_ALL_BUILTIN =
( OPENSSL_INIT_ENGINE_RDRAND | OPENSSL_INIT_ENGINE_DYNAMIC | OPENSSL_INIT_ENGINE_CRYPTODEV | OPENSSL_INIT_ENGINE_CAPI | OPENSSL_INIT_ENGINE_PADLOCK )
- OPENSSL_INIT_LOAD_SSL_STRINGS =
OpenSSL 1.1.0 load strings constant, taken from: github.com/openssl/openssl/blob/c162c126be342b8cd97996346598ecf7db56130f/include/openssl/ssl.h
0x00200000
Class Method Summary collapse
- .BN_num_bytes(ptr) ⇒ Object
- .init_ffi_ssl ⇒ Object
- .recover_compact(hash, signature) ⇒ Object
- .recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed) ⇒ Object
- .sign_compact(hash, private_key, public_key_hex) ⇒ Object
-
.version ⇒ Integer
Returns the version of SSL present.
Class Method Details
.BN_num_bytes(ptr) ⇒ Object
108 109 110 |
# File 'lib/eth/open_ssl.rb', line 108 def BN_num_bytes(ptr) (BN_num_bits(ptr) + 7) / 8 end |
.init_ffi_ssl ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/eth/open_ssl.rb', line 225 def init_ffi_ssl return if @ssl_loaded if version >= VERSION_1_1_0_NUM OPENSSL_init_ssl( OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN, nil ) else SSL_library_init() ERR_load_crypto_strings() SSL_load_error_strings() end RAND_poll() @ssl_loaded = true end |
.recover_compact(hash, signature) ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/eth/open_ssl.rb', line 207 def recover_compact(hash, signature) return false if signature.bytesize != 65 version = signature.unpack('C')[0] # Version of signature should be 27 or 28, but 0 and 1 are also possible versions # which can show up in Ledger hardwallet signings if version < 27 version += 27 end v_base = Eth.replayable_v?(version) ? Eth.replayable_chain_id : Eth.v_base return false if version < v_base recover_public_key_from_signature(hash, signature, (version - v_base), false) end |
.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/eth/open_ssl.rb', line 153 def recover_public_key_from_signature(, signature, rec_id, is_compressed) return nil if rec_id < 0 or signature.bytesize != 65 init_ffi_ssl signature = FFI::MemoryPointer.from_string(signature) r = BN_bin2bn(signature[1], 32, BN_new()) s = BN_bin2bn(signature[33], 32, BN_new()) _n, i = 0, rec_id / 2 eckey = EC_KEY_new_by_curve_name(NID_secp256k1) EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed group = EC_KEY_get0_group(eckey) order = BN_new() EC_GROUP_get_order(group, order, nil) x = BN_dup(order) BN_mul_word(x, i) BN_add(x, x, r) field = BN_new() EC_GROUP_get_curve_GFp(group, field, nil, nil, nil) if BN_cmp(x, field) >= 0 bn_free_each r, s, order, x, field EC_KEY_free(eckey) return nil end big_r = EC_POINT_new(group) EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil) big_q = EC_POINT_new(group) n = EC_GROUP_get_degree(group) e = BN_bin2bn(, .bytesize, BN_new()) BN_rshift(e, e, 8 - (n & 7)) if 8 * .bytesize > n ctx = BN_CTX_new() zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new() BN_set_word(zero, 0) BN_mod_sub(e, zero, e, order, ctx) BN_mod_inverse(rr, r, order, ctx) BN_mod_mul(sor, s, rr, order, ctx) BN_mod_mul(eor, e, rr, order, ctx) EC_POINT_mul(group, big_q, eor, big_r, sor, ctx) EC_KEY_set_public_key(eckey, big_q) BN_CTX_free(ctx) bn_free_each r, s, order, x, field, e, zero, rr, sor, eor [big_r, big_q].each{|j| EC_POINT_free(j) } recover_public_hex eckey end |
.sign_compact(hash, private_key, public_key_hex) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/eth/open_ssl.rb', line 112 def sign_compact(hash, private_key, public_key_hex) private_key = [private_key].pack("H*") if private_key.bytesize >= 64 pubkey_compressed = false init_ffi_ssl eckey = EC_KEY_new_by_curve_name(NID_secp256k1) priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new()) group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new() EC_GROUP_get_order(group, order, ctx) pub_key = EC_POINT_new(group) EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx) EC_KEY_set_private_key(eckey, priv_key) EC_KEY_set_public_key(eckey, pub_key) signature = ECDSA_do_sign(hash, hash.bytesize, eckey) BN_free(order) BN_CTX_free(ctx) EC_POINT_free(pub_key) BN_free(priv_key) EC_KEY_free(eckey) buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil r, s = signature.get_array_of_pointer(0, 2).map{|i| BN_bn2bin(i, buf); buf.read_string(BN_num_bytes(i)).rjust(32, "\x00") } if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 } 4.times{|i| head = [ Eth.v_base + i ].pack("C") if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed) rec_id = i; break end } end ECDSA_SIG_free(signature) [ head, [r,s] ].join if rec_id end |
.version ⇒ Integer
Returns the version of SSL present.
56 57 58 59 60 61 62 |
# File 'lib/eth/open_ssl.rb', line 56 def self.version if self.respond_to?(:OpenSSL_version_num) OpenSSL_version_num() else SSLeay() end end |