@@ -10,16 +10,68 @@ module OpenSSL_EC # rubocop:disable Naming/ClassAndModuleCamelCase
1010 if FFI ::Platform . windows?
1111 ffi_lib 'libeay32' , 'ssleay32'
1212 else
13- ffi_lib [ 'libssl.so.1.0.0' , 'ssl' ]
13+ ffi_lib [
14+ 'libssl.so.1.1.0' , 'libssl.so.1.1' ,
15+ 'libssl.so.1.0.0' , 'libssl.so.10' ,
16+ 'ssl'
17+ ]
1418 end
1519
1620 NID_secp256k1 = 714 # rubocop:disable Naming/ConstantName
1721 POINT_CONVERSION_COMPRESSED = 2
1822 POINT_CONVERSION_UNCOMPRESSED = 4
1923
20- attach_function :SSL_library_init , [ ] , :int
21- attach_function :ERR_load_crypto_strings , [ ] , :void
22- attach_function :SSL_load_error_strings , [ ] , :void
24+ # OpenSSL 1.1.0 version as a numerical version value as defined in:
25+ # https://www.openssl.org/docs/man1.1.0/man3/OpenSSL_version.html
26+ VERSION_1_1_0_NUM = 0x10100000
27+
28+ # OpenSSL 1.1.0 engine constants, taken from:
29+ # https://github.com/openssl/openssl/blob/2be8c56a39b0ec2ec5af6ceaf729df154d784a43/include/openssl/crypto.h
30+ OPENSSL_INIT_ENGINE_RDRAND = 0x00000200
31+ OPENSSL_INIT_ENGINE_DYNAMIC = 0x00000400
32+ OPENSSL_INIT_ENGINE_CRYPTODEV = 0x00001000
33+ OPENSSL_INIT_ENGINE_CAPI = 0x00002000
34+ OPENSSL_INIT_ENGINE_PADLOCK = 0x00004000
35+ OPENSSL_INIT_ENGINE_ALL_BUILTIN = (
36+ OPENSSL_INIT_ENGINE_RDRAND |
37+ OPENSSL_INIT_ENGINE_DYNAMIC |
38+ OPENSSL_INIT_ENGINE_CRYPTODEV |
39+ OPENSSL_INIT_ENGINE_CAPI |
40+ OPENSSL_INIT_ENGINE_PADLOCK
41+ )
42+
43+ # OpenSSL 1.1.0 load strings constant, taken from:
44+ # https://github.com/openssl/openssl/blob/c162c126be342b8cd97996346598ecf7db56130f/include/openssl/ssl.h
45+ OPENSSL_INIT_LOAD_SSL_STRINGS = 0x00200000
46+
47+ # This is the very first function we need to use to determine what version
48+ # of OpenSSL we are interacting with.
49+ begin
50+ attach_function :OpenSSL_version_num , [ ] , :ulong
51+ rescue FFI ::NotFoundError
52+ attach_function :SSLeay , [ ] , :long
53+ end
54+
55+ # Returns the version of SSL present.
56+ #
57+ # @return [Integer] version number as an integer.
58+ def self . version
59+ if self . respond_to? ( :OpenSSL_version_num )
60+ OpenSSL_version_num ( )
61+ else
62+ SSLeay ( )
63+ end
64+ end
65+
66+ if version >= VERSION_1_1_0_NUM
67+ # Initialization procedure for the library was changed in OpenSSL 1.1.0
68+ attach_function :OPENSSL_init_ssl , [ :uint64 , :pointer ] , :int
69+ else
70+ attach_function :SSL_library_init , [ ] , :int
71+ attach_function :ERR_load_crypto_strings , [ ] , :void
72+ attach_function :SSL_load_error_strings , [ ] , :void
73+ end
74+
2375 attach_function :RAND_poll , [ ] , :int
2476
2577 attach_function :BN_CTX_free , [ :pointer ] , :int
@@ -28,7 +80,6 @@ module OpenSSL_EC # rubocop:disable Naming/ClassAndModuleCamelCase
2880 attach_function :BN_bin2bn , %i[ pointer int pointer ] , :pointer
2981 attach_function :BN_bn2bin , %i[ pointer pointer ] , :int
3082 attach_function :BN_cmp , %i[ pointer pointer ] , :int
31- attach_function :BN_copy , %i[ pointer pointer ] , :pointer
3283 attach_function :BN_dup , [ :pointer ] , :pointer
3384 attach_function :BN_free , [ :pointer ] , :int
3485 attach_function :BN_mod_inverse , %i[ pointer pointer pointer pointer ] , :pointer
@@ -51,22 +102,17 @@ module OpenSSL_EC # rubocop:disable Naming/ClassAndModuleCamelCase
51102 attach_function :EC_KEY_set_private_key , %i[ pointer pointer ] , :int
52103 attach_function :EC_KEY_set_public_key , %i[ pointer pointer ] , :int
53104 attach_function :EC_POINT_free , [ :pointer ] , :int
54- attach_function :EC_POINT_is_at_infinity , %i[ pointer pointer ] , :int
55105 attach_function :EC_POINT_mul , %i[ pointer pointer pointer pointer pointer pointer ] , :int
56106 attach_function :EC_POINT_new , [ :pointer ] , :pointer
57107 attach_function :EC_POINT_set_compressed_coordinates_GFp ,
58108 %i[ pointer pointer pointer int pointer ] , :int
59- attach_function :d2i_ECPrivateKey , %i[ pointer pointer long ] , :pointer
60- attach_function :i2d_ECPrivateKey , %i[ pointer pointer ] , :int
61109 attach_function :i2o_ECPublicKey , %i[ pointer pointer ] , :uint
62- attach_function :EC_KEY_check_key , [ :pointer ] , :uint
63110 attach_function :ECDSA_do_sign , %i[ pointer uint pointer ] , :pointer
64111 attach_function :BN_num_bits , [ :pointer ] , :int
65112 attach_function :ECDSA_SIG_free , [ :pointer ] , :void
66113 attach_function :EC_POINT_add , %i[ pointer pointer pointer pointer pointer ] , :int
67114 attach_function :EC_POINT_point2hex , %i[ pointer pointer int pointer ] , :string
68115 attach_function :EC_POINT_hex2point , %i[ pointer string pointer pointer ] , :pointer
69- attach_function :ECDSA_SIG_new , [ ] , :pointer
70116 attach_function :d2i_ECDSA_SIG , %i[ pointer pointer long ] , :pointer
71117 attach_function :i2d_ECDSA_SIG , %i[ pointer pointer ] , :int
72118 attach_function :OPENSSL_free , :CRYPTO_free , [ :pointer ] , :void
@@ -82,68 +128,17 @@ def self.regenerate_key(private_key)
82128 private_key = [ private_key ] . pack ( 'H*' ) if private_key . bytesize >= ( 32 * 2 )
83129 private_key_hex = private_key . unpack ( 'H*' ) [ 0 ]
84130
85- # private_key = FFI::MemoryPointer.new(:uint8, private_key.bytesize)
86- # .put_bytes(0, private_key, 0, private_key.bytesize)
87- private_key = FFI ::MemoryPointer . from_string ( private_key )
88-
89- init_ffi_ssl
90- eckey = EC_KEY_new_by_curve_name ( NID_secp256k1 )
91- # priv_key = BN_bin2bn(private_key, private_key.size, BN_new())
92- priv_key = BN_bin2bn ( private_key , private_key . size - 1 , BN_new ( ) )
93-
94- group = EC_KEY_get0_group ( eckey )
95- order = BN_new ( )
96- ctx = BN_CTX_new ( )
97- EC_GROUP_get_order ( group , order , ctx )
98-
99- pub_key = EC_POINT_new ( group )
100- EC_POINT_mul ( group , pub_key , priv_key , nil , nil , ctx )
101- EC_KEY_set_private_key ( eckey , priv_key )
102- EC_KEY_set_public_key ( eckey , pub_key )
103-
104- BN_free ( order )
105- BN_CTX_free ( ctx )
106- EC_POINT_free ( pub_key )
107- BN_free ( priv_key )
108-
109- length = i2d_ECPrivateKey ( eckey , nil )
110- buf = FFI ::MemoryPointer . new ( :uint8 , length )
111- ptr = FFI ::MemoryPointer . new ( :pointer ) . put_pointer ( 0 , buf )
112- priv_hex = if i2d_ECPrivateKey ( eckey , ptr ) == length
113- size = buf . get_array_of_uint8 ( 8 , 1 ) [ 0 ]
114- buf . get_array_of_uint8 ( 9 , size ) . pack ( 'C*' ) . rjust ( 32 , "\x00 " ) . unpack ( 'H*' ) [ 0 ]
115- # der_to_private_key( ptr.read_pointer.read_string(length).unpack("H*")[0] )
116- end
131+ group = OpenSSL ::PKey ::EC ::Group . new ( 'secp256k1' )
132+ key = OpenSSL ::PKey ::EC . new ( group )
133+ key . private_key = OpenSSL ::BN . new ( private_key_hex , 16 )
134+ key . public_key = group . generator . mul ( key . private_key )
117135
136+ priv_hex = key . private_key . to_bn . to_s ( 16 ) . downcase . rjust ( 64 , '0' )
118137 if priv_hex != private_key_hex
119138 raise 'regenerated wrong private_key, raise here before generating a faulty public_key too!'
120139 end
121140
122- length = i2o_ECPublicKey ( eckey , nil )
123- buf = FFI ::MemoryPointer . new ( :uint8 , length )
124- ptr = FFI ::MemoryPointer . new ( :pointer ) . put_pointer ( 0 , buf )
125- pub_hex = buf . read_string ( length ) . unpack ( 'H*' ) [ 0 ] if i2o_ECPublicKey ( eckey , ptr ) == length
126-
127- EC_KEY_free ( eckey )
128-
129- [ priv_hex , pub_hex ]
130- end
131-
132- # extract private key from uncompressed DER format
133- def self . der_to_private_key ( der_hex )
134- init_ffi_ssl
135- # k = EC_KEY_new_by_curve_name(NID_secp256k1)
136- # kp = FFI::MemoryPointer.new(:pointer).put_pointer(0, eckey)
137-
138- buf = FFI ::MemoryPointer . from_string ( [ der_hex ] . pack ( 'H*' ) )
139- ptr = FFI ::MemoryPointer . new ( :pointer ) . put_pointer ( 0 , buf )
140-
141- # ec_key = d2i_ECPrivateKey(kp, ptr, buf.size-1)
142- ec_key = d2i_ECPrivateKey ( nil , ptr , buf . size - 1 )
143- return nil if ec_key . null?
144- bn = EC_KEY_get0_private_key ( ec_key )
145- BN_bn2bin ( bn , buf )
146- buf . read_string ( 32 ) . unpack ( 'H*' ) [ 0 ]
141+ [ priv_hex , key . public_key . to_bn . to_s ( 16 ) . downcase ]
147142 end
148143
149144 # Given the components of a signature and a selector value, recover and
@@ -395,9 +390,18 @@ def self.repack_der_signature(signature)
395390 def self . init_ffi_ssl
396391 @ssl_loaded ||= false
397392 return if @ssl_loaded
398- SSL_library_init ( )
399- ERR_load_crypto_strings ( )
400- SSL_load_error_strings ( )
393+
394+ if version >= VERSION_1_1_0_NUM
395+ OPENSSL_init_ssl (
396+ OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_ENGINE_ALL_BUILTIN ,
397+ nil
398+ )
399+ else
400+ SSL_library_init ( )
401+ ERR_load_crypto_strings ( )
402+ SSL_load_error_strings ( )
403+ end
404+
401405 RAND_poll ( )
402406 @ssl_loaded = true
403407 end
0 commit comments