roqs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/README.md +128 -0
- data/Rakefile +9 -0
- data/TEST-RESULT.md +68 -0
- data/lib/roqs/common_wrapper.rb +20 -0
- data/lib/roqs/kem.rb +148 -0
- data/lib/roqs/kem_public_key.rb +28 -0
- data/lib/roqs/kem_wrapper.rb +28 -0
- data/lib/roqs/sig.rb +99 -0
- data/lib/roqs/sig_wrapper.rb +31 -0
- data/lib/roqs/struct.rb +35 -0
- data/lib/roqs/version.rb +5 -0
- data/lib/roqs/wrapper.rb +79 -0
- data/lib/roqs.rb +42 -0
- data/native/linux/x86_64/liboqs.so.0.9.0 +0 -0
- data/native/macos/x86_64/liboqs.0.7.0.dylib +0 -0
- data/native/windows/x64/liboqs.dll +0 -0
- data/sig/roqs.rbs +4 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f19a8901d58a30e6f96bc3a69edd4674c5a2c64bc9acc017b806c6617961c0dd
|
4
|
+
data.tar.gz: 86a3ad02995a7d908818d11d185510faee8ead854611266737af43fe5f2410b1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fe26fcb62c00f7622d35d2560b3183fab2d2917b4b90755fd58ffeaedbd4ceda0ca1faf405ed4e84a2baea5ab890ce085760bad4826fda434c7cc29964ab53c6
|
7
|
+
data.tar.gz: 16a08e37b93c050424969e5a64dce0a780379304cabf1d864bfb91d838a73f74bb4b89aebffa45e7edb44344f3061508bef2e2ec656122dd4718556b3d485544
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/README.md
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# Roqs
|
2
|
+
|
3
|
+
Roqs is the Ruby wrapper to the [Open Quantum Safe library](https://openquantumsafe.org). The native library was tested against the liboqs at [liboqs](https://github.com/open-quantum-safe/liboqs)
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'roqs'
|
10
|
+
```
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle install
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install roqs
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
OQS mainly only has two group of functions: Key Encapsulation Mechanism (KEM) and Signature (SIG).
|
23
|
+
|
24
|
+
Therefore the Ruby wrapper abstraction is following the liboqs C version as baseline.
|
25
|
+
|
26
|
+
### Key Encapsulation Mechanism (KEM)
|
27
|
+
|
28
|
+
For KEM, the API is simple:
|
29
|
+
|
30
|
+
1. List all supported KEM PQ algorithms - PQ algorithms can be enable or disabled at compile time so it all depends on the liboqs native library. This API listed down the algorithms which are *supported* as reported by the native library. If you're using your own version of the library, you might have different output.
|
31
|
+
```ruby
|
32
|
+
require 'roqs'
|
33
|
+
|
34
|
+
supported_algo = Roqs::KEM.supported_kem_algo
|
35
|
+
supported_algo.each do |al|
|
36
|
+
# al is the algorithm name (string) which is required by subsequent API
|
37
|
+
...
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
2. Generate keypair
|
42
|
+
```ruby
|
43
|
+
require 'roqs'
|
44
|
+
|
45
|
+
kyber = Roqs::KEM.new('Kyber768')
|
46
|
+
pubKey, secretKey = kyber.genkeypair
|
47
|
+
# note pubKey and secretKey (or private key) is Fiddle::Pointer type and
|
48
|
+
# is required to be used by the C API in the subsequent phase.
|
49
|
+
# Note that pubKey and secretKey are required to be free manually
|
50
|
+
# Refer spec file for usage
|
51
|
+
```
|
52
|
+
|
53
|
+
3. Key encapsulation - KEM is meant for key encapsulation which similar with Diffie-Hellman kind of key exchange
|
54
|
+
```ruby
|
55
|
+
require 'roqs'
|
56
|
+
|
57
|
+
sessionKey, cipher = kyber.derive_encapsulation_key(pubKey)
|
58
|
+
# cipher is required to be sent to recipient end to re-generate the sessionKey at recipient end.
|
59
|
+
# Returned sessionKey is meant to convert into the final AES (or any other symmetric key)
|
60
|
+
# for the actual data encryption
|
61
|
+
```
|
62
|
+
|
63
|
+
4. Key decapsulation - Re-generate the session key from the private key
|
64
|
+
```ruby
|
65
|
+
require 'roqs'
|
66
|
+
|
67
|
+
sessionKey = kyber.derive_decapsulation_key(cipher, secretKey)
|
68
|
+
# cipher is given by sender and privKey is the recipient own private key
|
69
|
+
```
|
70
|
+
|
71
|
+
_sessionKey_ returned from derive\_encapsulation\_key() shall be same as the _sessionKey_ from derive\_decapsulation\_key(). That session key shall be the AES key (any other symmetric key) for the data encryption.
|
72
|
+
|
73
|
+
|
74
|
+
### Signature mechanism
|
75
|
+
|
76
|
+
Signature mechanism is similar with KEM.
|
77
|
+
|
78
|
+
1. List all supported Signature PQ algorithms - It is same as KEM as algorithm can be turned on or off during compile time
|
79
|
+
```ruby
|
80
|
+
require 'roqs'
|
81
|
+
|
82
|
+
supported_algo = Roqs::SIG.supported_signature_algo
|
83
|
+
supported_algo.each do |al|
|
84
|
+
# al is the algorithm name (string) which is required by subsequent API
|
85
|
+
...
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
2. Generate keypair
|
90
|
+
```ruby
|
91
|
+
require 'roqs'
|
92
|
+
|
93
|
+
dili = Roqs::SIG.new('Dilithium5')
|
94
|
+
pubKey, secretKey = dili.genkeypair
|
95
|
+
# note pubKey and secretKey (or private key) is Fiddle::Pointer type and
|
96
|
+
# is required to be used by the C API in the subsequent phase.
|
97
|
+
# Note that pubKey and secretKey are required to be free manually
|
98
|
+
# Refer spec file for usage
|
99
|
+
```
|
100
|
+
|
101
|
+
3. Generate data signature
|
102
|
+
```rubyion
|
103
|
+
require 'roqs'
|
104
|
+
|
105
|
+
# sign data using sender secretKey/private key
|
106
|
+
signature = dili.sign("this is message", secretKey)
|
107
|
+
```
|
108
|
+
|
109
|
+
4. Verify data signature
|
110
|
+
```ruby
|
111
|
+
require 'roqs'
|
112
|
+
|
113
|
+
# verify signature with given data using sender public key
|
114
|
+
res = dili.verify("this is message", signature, pubKey)
|
115
|
+
# res is boolean to indicate the signature verification is passed or failed
|
116
|
+
```
|
117
|
+
|
118
|
+
spec folder has the necessary API example usage.
|
119
|
+
|
120
|
+
|
121
|
+
## Test Results
|
122
|
+
|
123
|
+
Refer to [test result](https://github.com/chrisliaw/liboqs-ruby/blob/master/TEST-RESULT.md) for details.
|
124
|
+
|
125
|
+
## License
|
126
|
+
|
127
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
128
|
+
|
data/Rakefile
ADDED
data/TEST-RESULT.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
# The following are test results for release roqs-0.1.0
|
3
|
+
|
4
|
+
liboqs-0.9.0 has less PQ algorithms and includes all 4 + 3 of the [finalist in the NIST PQC Standardization Candidates](https://csrc.nist.gov/news/2022/pqc-candidates-to-be-standardized-and-round-4)
|
5
|
+
## Development Environment
|
6
|
+
|
7
|
+
The source code was tested on
|
8
|
+
* Linux: Ruby MRI 3.2.1 (2023-02-08 revision 31819e82c8) [x86\_64-linux], Linux Mint 21.2 x86\_64, Kernel 5.15.0-88-generic, CMake version 3.22.1, Ninja 1.10.1
|
9
|
+
|
10
|
+
## Testing result
|
11
|
+
|
12
|
+
The following test result is by running the rspec.
|
13
|
+
|
14
|
+
The compiled liboqs version 0.9.0 library on Linux works flawlessly.
|
15
|
+
|
16
|
+
Unfornately I've lost access to MacOS. Any help would be gladely appreciated.
|
17
|
+
|
18
|
+
All KEM and SIG algos supported completed all major operations such as keygen, sign/verify, encap/decap without error.
|
19
|
+
|
20
|
+
|
21
|
+
### Windows (Coming Soon)
|
22
|
+
|
23
|
+
# The following are the test results for liboqs version 0.7.0 (before NIST finalist was published. It may not relevent for now just for history purposes)
|
24
|
+
## Development Environment
|
25
|
+
|
26
|
+
The source code was tested on
|
27
|
+
* Linux: Ruby MRI 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux], Linux Mint 20.2 x86_64, Kernel 5.4.0-81-generic, Intel i7-9750H, CMake version 3.16.3, Ninja 1.10.0
|
28
|
+
* MacOS: Ruby MRI 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86\_64-darwin20], Mac OS BigSur 11.5, 2.5GHz Quad-Core Intel Core i7, Apple clang version 12.0.5 (clang-1205.0.22.11), CMake version 3.21.1, Ninja 1.10.2
|
29
|
+
* Windows: Ruby MRI 3.0.2p107 (2021-07-07 revision 0db68f02333) [x64-mingw32], Windows 10 64 bits, Microsoft C/C++ compiler v 19.25.28610.4, Intel i7-9750H, CMake version 3.16.19112601-MSVC\_2, Ninja 1.8.2
|
30
|
+
|
31
|
+
## Testing result
|
32
|
+
|
33
|
+
The following test result is by running the rspec.
|
34
|
+
|
35
|
+
The compiled liboqs version 0.7.0 library on Linux works flawlessly on respective OS.
|
36
|
+
|
37
|
+
All KEM and SIG algos supported completed all major operations such as keygen, sign/verify, encap/decap without error.
|
38
|
+
|
39
|
+
|
40
|
+
### Windows (Cross Compiling)
|
41
|
+
|
42
|
+
Cross compiling DLL for Windows on Linux with MingW toolchain failed with:
|
43
|
+
For KEM:
|
44
|
+
* BIKE-L1 & BIKE-L3 failed where library return null. Both running ok on Linux and MacOS
|
45
|
+
* Stack level too deep with all Classic-McEliece family of algo. All algo of Classic-McEliece-xxxx not able to execute.
|
46
|
+
* Stagmentation fault for SIDH-p503, SIDH-p503-compressed, SIDH-p751, SIDH-p751-compressed, SIKE-p503, SIKE-p751, SIKE-p503-compressed and SIKE-p751-compressed
|
47
|
+
|
48
|
+
For SIG:
|
49
|
+
* Stack level too deep for Rainbow-V-Classic, Rainbow-V-Circumzenithal and Rainbow-V-Compressed
|
50
|
+
|
51
|
+
Test cases not able to proceed after "Stack level too deep" exception. Not sure due to Ruby or native library
|
52
|
+
|
53
|
+
### Windows (Native build)
|
54
|
+
|
55
|
+
Native compile oqs library on Windows however have different result:
|
56
|
+
For KEM:
|
57
|
+
* BIKE-L1 & BIKE-L3 failed where library return null. Both running ok on Linux and MacOS
|
58
|
+
* Stack level too deep with all Classic-McEliece family of algo. All algo of Classic-McEliece-xxxx not able to execute.
|
59
|
+
|
60
|
+
For SIG
|
61
|
+
* Rainbow-V still crash
|
62
|
+
|
63
|
+
Rainbow feels taking longer time on Windows compare to Linux/Mac?
|
64
|
+
Sphincs slow too
|
65
|
+
|
66
|
+
But SIDH-xxx and SIKE-xxx family passed on native build
|
67
|
+
|
68
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require 'fiddle'
|
3
|
+
require 'fiddle/import'
|
4
|
+
|
5
|
+
module Roqs
|
6
|
+
module CommonWrapper
|
7
|
+
extend Fiddle::Importer
|
8
|
+
include Roqs::Wrapper
|
9
|
+
|
10
|
+
#dlload File.join(File.dirname(__FILE__),"..","..","native","linux","x86_64","liboqs.so.0.7.0")
|
11
|
+
load_oqs_lib
|
12
|
+
|
13
|
+
extern 'int OQS_MEM_secure_bcmp(const void *a, const void *b, size_t len)'
|
14
|
+
extern 'int OQS_MEM_cleanse(const void *ptr, size_t len)'
|
15
|
+
extern 'int OQS_MEM_secure_free(void *ptr, size_t len)'
|
16
|
+
extern 'int OQS_MEM_insecure_free(void *ptr)'
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/roqs/kem.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
|
2
|
+
require_relative 'struct'
|
3
|
+
require_relative 'kem_wrapper'
|
4
|
+
require_relative 'common_wrapper'
|
5
|
+
|
6
|
+
require_relative 'kem_public_key'
|
7
|
+
|
8
|
+
module Roqs
|
9
|
+
class KEM
|
10
|
+
|
11
|
+
def self.supported_kem_algo
|
12
|
+
ttl = KEMWrapper.OQS_KEM_alg_count
|
13
|
+
supported = []
|
14
|
+
(0...ttl).each do |i|
|
15
|
+
pName = KEMWrapper.OQS_KEM_alg_identifier(i)
|
16
|
+
name = pName.to_s
|
17
|
+
st = KEMWrapper.OQS_KEM_alg_is_enabled(name)
|
18
|
+
if st
|
19
|
+
supported << name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
supported
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(name)
|
27
|
+
@algo = name
|
28
|
+
oqsKem = KEMWrapper.OQS_KEM_new(@algo)
|
29
|
+
raise Error, "Unable to create object '#{@algo}'. It is either the algorithm not supported or it is disabled at compile time." if oqsKem.null?
|
30
|
+
@struct = OQS_KEM.new(oqsKem)
|
31
|
+
end
|
32
|
+
|
33
|
+
def cleanup
|
34
|
+
KEMWrapper.OQS_KEM_free(@struct) if not @struct.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def free(obj)
|
38
|
+
obj.free if not (obj.nil? and obj.null?)
|
39
|
+
end
|
40
|
+
|
41
|
+
def intrinsic_name
|
42
|
+
@struct.intrinsic_name.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
def algo_version
|
46
|
+
@struct.algo_version.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(mtd, *args, &block)
|
50
|
+
@struct.send(mtd) if not @struct.nil? and @struct.respond_to?(mtd)
|
51
|
+
end
|
52
|
+
|
53
|
+
def genkeypair
|
54
|
+
pubKey = Fiddle::Pointer.malloc(@struct.length_public_key, Fiddle::RUBY_FREE)
|
55
|
+
raise Error, "Unable to allocate memory for public key size #{@struct.length_public_key}" if pubKey.null?
|
56
|
+
privKey = Fiddle::Pointer.malloc(@struct.length_secret_key, Fiddle::RUBY_FREE)
|
57
|
+
raise Error, "Unable to allocate memory for secret key size #{@struct.length_secret_key}" if privKey.null?
|
58
|
+
|
59
|
+
rv = KEMWrapper.OQS_KEM_keypair(@struct, pubKey, privKey)
|
60
|
+
raise Error, "Error in generation of keypair" if rv != Roqs::OQS_SUCCESS
|
61
|
+
|
62
|
+
#pubKeyBin = pubKey[0, pubKey.size]
|
63
|
+
#privKeyBin = privKey[0, privKey.size]
|
64
|
+
|
65
|
+
[KEMPublicKey.new(pubKey), privKey]
|
66
|
+
end
|
67
|
+
|
68
|
+
def derive_encapsulation_key(pubKey)
|
69
|
+
|
70
|
+
cipher = Fiddle::Pointer.malloc(@struct.length_ciphertext, Fiddle::RUBY_FREE)
|
71
|
+
raise Error, "Unable to allocate memory for ciphertext size #{@struct.length_ciphertext}" if cipher.null?
|
72
|
+
|
73
|
+
encpKey = Fiddle::Pointer.malloc(@struct.length_shared_secret, Fiddle::RUBY_FREE)
|
74
|
+
raise Error, "Unable to allocate memory for shared secret size #{@struct.length_shared_secret}" if encpKey.null?
|
75
|
+
|
76
|
+
rv = KEMWrapper.OQS_KEM_encaps(@struct, cipher, encpKey, pubKey)
|
77
|
+
raise Error, "Error in encapsulation" if rv != Roqs::OQS_SUCCESS
|
78
|
+
|
79
|
+
encpKeyBin = encpKey[0,encpKey.size]
|
80
|
+
cipherBin = cipher[0,cipher.size]
|
81
|
+
|
82
|
+
cipher.free
|
83
|
+
encpKey.free
|
84
|
+
|
85
|
+
[encpKeyBin, cipherBin]
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def derive_decapsulation_key(cipherBin, privKey)
|
90
|
+
|
91
|
+
raise Error, "Cipher cannot be empty" if cipherBin.nil?
|
92
|
+
raise Error, "Private key cannot be nil" if privKey.nil?
|
93
|
+
|
94
|
+
encpKey = Fiddle::Pointer.malloc(@struct.length_shared_secret, Fiddle::RUBY_FREE)
|
95
|
+
raise Error, "Unable to allocate memory for shared secret size #{@struct.length_shared_secret}" if encpKey.null?
|
96
|
+
|
97
|
+
rv = KEMWrapper.OQS_KEM_decaps(@struct, encpKey , cipherBin, privKey)
|
98
|
+
raise Error, "Error in decapsulation" if rv != Roqs::OQS_SUCCESS
|
99
|
+
|
100
|
+
encpKeyBin = encpKey[0,encpKey.size]
|
101
|
+
|
102
|
+
encpKey.free
|
103
|
+
|
104
|
+
encpKeyBin
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
#def test
|
109
|
+
|
110
|
+
# @cipher = Fiddle::Pointer.malloc(@struct.length_ciphertext, Fiddle::RUBY_FREE)
|
111
|
+
# raise Error, "Unable to allocate memory for ciphertext size #{@struct.length_ciphertext}" if @cipher.null?
|
112
|
+
|
113
|
+
# shared_e = Fiddle::Pointer.malloc(@struct.length_shared_secret, Fiddle::RUBY_FREE)
|
114
|
+
# raise Error, "Unable to allocate memory for shared secret size #{@struct.length_shared_secret}" if shared_e.null?
|
115
|
+
#
|
116
|
+
# shared_d = Fiddle::Pointer.malloc(@struct.length_shared_secret, Fiddle::RUBY_FREE)
|
117
|
+
# raise Error, "Unable to allocate memory for shared secret size #{@struct.length_shared_secret}" if shared_d.null?
|
118
|
+
|
119
|
+
# shared_x = Fiddle::Pointer.malloc(@struct.length_shared_secret, Fiddle::RUBY_FREE)
|
120
|
+
#
|
121
|
+
# p shared_e.ptr == shared_d.ptr
|
122
|
+
|
123
|
+
# rb = shared_e[0, shared_e.size]
|
124
|
+
# p rb
|
125
|
+
|
126
|
+
# rv = KEMWrapper.OQS_KEM_encaps(@struct, @cipher, shared_e, @pubKey)
|
127
|
+
# raise Error, "Error in encapsulation" if rv != KEMWrapper::OQS_SUCCESS
|
128
|
+
|
129
|
+
# rb = shared_e[0, shared_e.size]
|
130
|
+
# p rb
|
131
|
+
|
132
|
+
# p shared_e.ptr == shared_d.ptr
|
133
|
+
|
134
|
+
# rv = KEMWrapper.OQS_KEM_decaps(@struct, shared_d, @cipher, @privKey)
|
135
|
+
# raise Error, "Error in decapsulation" if rv != KEMWrapper::OQS_SUCCESS
|
136
|
+
|
137
|
+
# p shared_e.ptr == shared_d.ptr
|
138
|
+
|
139
|
+
# p shared_d.size
|
140
|
+
# rb = shared_d[0, shared_d.size]
|
141
|
+
# p rb
|
142
|
+
|
143
|
+
|
144
|
+
#end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require_relative 'struct'
|
3
|
+
require_relative 'kem_wrapper'
|
4
|
+
require_relative 'common_wrapper'
|
5
|
+
|
6
|
+
module Roqs
|
7
|
+
class KEMPublicKey
|
8
|
+
|
9
|
+
def initialize(nativePubKey)
|
10
|
+
@native_pubkey = nativePubKey
|
11
|
+
end
|
12
|
+
|
13
|
+
def length
|
14
|
+
@native_pubkey.size
|
15
|
+
end
|
16
|
+
|
17
|
+
def bytes
|
18
|
+
#puts "raw 1 : #{@native_pubkey.size}"
|
19
|
+
#puts "raw 2 : #{@native_pubkey.to_str}"
|
20
|
+
@native_pubkey.to_str
|
21
|
+
end
|
22
|
+
|
23
|
+
def native_pubkey
|
24
|
+
@native_pubkey
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require 'fiddle'
|
3
|
+
require 'fiddle/import'
|
4
|
+
|
5
|
+
require_relative 'wrapper'
|
6
|
+
|
7
|
+
module Roqs
|
8
|
+
module KEMWrapper
|
9
|
+
extend Fiddle::Importer
|
10
|
+
include Roqs::Wrapper
|
11
|
+
|
12
|
+
#dlload File.join(File.dirname(__FILE__),"..","..","native","linux","x86_64","liboqs.so.0.7.0")
|
13
|
+
load_oqs_lib
|
14
|
+
|
15
|
+
extern 'const char * OQS_KEM_alg_identifier(size_t i)'
|
16
|
+
extern 'int OQS_KEM_alg_count(void)'
|
17
|
+
extern 'int OQS_KEM_alg_is_enabled(const char * name)'
|
18
|
+
|
19
|
+
extern 'OQS_KEM * OQS_KEM_new(const char * algo)'
|
20
|
+
extern 'void OQS_KEM_free(OQS_KEM * kem)'
|
21
|
+
|
22
|
+
extern 'int OQS_KEM_keypair(const OQS_KEM *kem, uint8_t *public_key, uint8_t *secret_key)'
|
23
|
+
|
24
|
+
extern 'int OQS_KEM_encaps(const OQS_KEM *kem, uint8_t * ciphertext, uint8_t *shared_secret, uint8_t *public_key)'
|
25
|
+
extern 'int OQS_KEM_decaps(const OQS_KEM *kem, uint8_t * shared_secret, uint8_t *ciphertext, uint8_t *secret_key)'
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/lib/roqs/sig.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
|
2
|
+
require_relative 'struct'
|
3
|
+
require_relative 'sig_wrapper'
|
4
|
+
require_relative 'common_wrapper'
|
5
|
+
|
6
|
+
module Roqs
|
7
|
+
class SIG
|
8
|
+
|
9
|
+
def self.supported_signature_algo
|
10
|
+
ttl = SIGWrapper.OQS_SIG_alg_count
|
11
|
+
supported = []
|
12
|
+
(0...ttl).each do |i|
|
13
|
+
pName = SIGWrapper.OQS_SIG_alg_identifier(i)
|
14
|
+
name = pName.to_s
|
15
|
+
st = SIGWrapper.OQS_SIG_alg_is_enabled(name)
|
16
|
+
if st
|
17
|
+
supported << name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
supported
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(name)
|
25
|
+
@algo = name
|
26
|
+
oqsSig = SIGWrapper.OQS_SIG_new(@algo)
|
27
|
+
raise Error, "Unable to create object '#{@algo}'. It is either the algorithm not supported or it is disabled at compile time." if oqsSig.null?
|
28
|
+
@struct = OQS_SIG.new(oqsSig)
|
29
|
+
end
|
30
|
+
|
31
|
+
def cleanup
|
32
|
+
SIGWrapper.OQS_SIG_free(@struct) if not @struct.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def free(obj)
|
36
|
+
obj.free if not (obj.nil? and obj.null?)
|
37
|
+
end
|
38
|
+
|
39
|
+
def intrinsic_name
|
40
|
+
@struct.intrinsic_name.to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def algo_version
|
44
|
+
@struct.algo_version.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_missing(mtd, *args, &block)
|
48
|
+
@struct.send(mtd) if not @struct.nil? and @struct.respond_to?(mtd)
|
49
|
+
end
|
50
|
+
|
51
|
+
def genkeypair
|
52
|
+
pubKey = Fiddle::Pointer.malloc(@struct.length_public_key, Fiddle::RUBY_FREE)
|
53
|
+
raise Error, "Unable to allocate memory for public key size #{@struct.length_public_key}" if pubKey.null?
|
54
|
+
privKey = Fiddle::Pointer.malloc(@struct.length_secret_key, Fiddle::RUBY_FREE)
|
55
|
+
raise Error, "Unable to allocate memory for secret key size #{@struct.length_secret_key}" if privKey.null?
|
56
|
+
|
57
|
+
rv = SIGWrapper.OQS_SIG_keypair(@struct, pubKey, privKey)
|
58
|
+
raise Error, "Error in generation of keypair" if rv != Roqs::OQS_SUCCESS
|
59
|
+
|
60
|
+
[pubKey, privKey]
|
61
|
+
end
|
62
|
+
|
63
|
+
def verify(message,signature,pubKey)
|
64
|
+
|
65
|
+
pMessage = Fiddle::Pointer.to_ptr(message)
|
66
|
+
pSignature = Fiddle::Pointer.to_ptr(signature)
|
67
|
+
|
68
|
+
rv = SIGWrapper.OQS_SIG_verify(@struct, pMessage, message.length, pSignature, signature.length, pubKey)
|
69
|
+
|
70
|
+
rv == Roqs::OQS_SUCCESS
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def sign(message, privKey)
|
75
|
+
|
76
|
+
raise Error, "Private key cannot be nil" if privKey.nil?
|
77
|
+
|
78
|
+
signature = Fiddle::Pointer.malloc(@struct.length_signature, Fiddle::RUBY_FREE)
|
79
|
+
raise Error, "Unable to allocate memory for signature size #{@struct.length_signature}" if signature.null?
|
80
|
+
signLen = Fiddle::Pointer.malloc(Fiddle::SIZEOF_SIZE_T, Fiddle::RUBY_FREE)
|
81
|
+
raise Error, "Unable to allocate memory for signature length size #{Fiddle::SIZEOF_SIZE_T}" if signLen.null?
|
82
|
+
|
83
|
+
pMessage = Fiddle::Pointer.to_ptr(message)
|
84
|
+
|
85
|
+
rv = SIGWrapper.OQS_SIG_sign(@struct, signature, signLen, pMessage, message.length, privKey)
|
86
|
+
raise Error, "Error in signing" if rv != Roqs::OQS_SUCCESS
|
87
|
+
|
88
|
+
signBin = signature[0, signLen.ptr.to_i]
|
89
|
+
|
90
|
+
signLen.free
|
91
|
+
signature.free
|
92
|
+
|
93
|
+
signBin
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
require 'fiddle'
|
3
|
+
require 'fiddle/import'
|
4
|
+
|
5
|
+
module Roqs
|
6
|
+
module SIGWrapper
|
7
|
+
extend Fiddle::Importer
|
8
|
+
include Roqs::Wrapper
|
9
|
+
|
10
|
+
## OQS_STATUS
|
11
|
+
#OQS_ERROR = -1
|
12
|
+
#OQS_SUCCESS = 0
|
13
|
+
#OQS_EXTERNAL_LIB_ERROR_OPENSSL = 50
|
14
|
+
|
15
|
+
#dlload File.join(File.dirname(__FILE__),"..","..","native","linux","x86_64","liboqs.so.0.7.0")
|
16
|
+
load_oqs_lib
|
17
|
+
|
18
|
+
extern 'const char * OQS_SIG_alg_identifier(size_t i)'
|
19
|
+
extern 'int OQS_SIG_alg_count(void)'
|
20
|
+
extern 'int OQS_SIG_alg_is_enabled(const char * name)'
|
21
|
+
|
22
|
+
extern 'OQS_SIG * OQS_SIG_new(const char * algo)'
|
23
|
+
extern 'void OQS_SIG_free(OQS_SIG * sig)'
|
24
|
+
|
25
|
+
extern 'int OQS_SIG_keypair(const OQS_SIG *sig, uint8_t *public_key, uint8_t *secret_key)'
|
26
|
+
|
27
|
+
extern 'int OQS_SIG_sign(const OQS_SIG *sig, uint8_t * signature, size_t *signature_len, uint8_t *message, size_t message_len, uint8_t *secret_key)'
|
28
|
+
extern 'int OQS_SIG_verify(const OQS_SIG *sig, uint8_t * message, size_t message_len, uint8_t *signature, size_t signature_len, uint8_t *public_key)'
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/roqs/struct.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
require 'fiddle'
|
3
|
+
require 'fiddle/import'
|
4
|
+
|
5
|
+
module Roqs
|
6
|
+
extend Fiddle::Importer
|
7
|
+
|
8
|
+
OQS_KEM = struct [
|
9
|
+
"const char * intrinsic_name",
|
10
|
+
"const char * algo_version",
|
11
|
+
"uint8_t claimed_nist_level",
|
12
|
+
"int ind_cca",
|
13
|
+
"size_t length_public_key",
|
14
|
+
"size_t length_secret_key",
|
15
|
+
"size_t length_ciphertext",
|
16
|
+
"size_t length_shared_secret",
|
17
|
+
"int (*keypair)(uint8_t *pubKey, uint8_t* secretKey)",
|
18
|
+
"int (*encaps)(uint8_t *cipher_text, uint8_t* shared_secret, const unit8_t * pubKey)",
|
19
|
+
"int (*decaps)(uint8_t *shared_secret, uint8_t* cipher_text, const unit8_t * secretKey)"
|
20
|
+
]
|
21
|
+
|
22
|
+
OQS_SIG = struct [
|
23
|
+
"const char * intrinsic_name",
|
24
|
+
"const char * algo_version",
|
25
|
+
"uint8_t claimed_nist_level",
|
26
|
+
"int euf_cma",
|
27
|
+
"size_t length_public_key",
|
28
|
+
"size_t length_secret_key",
|
29
|
+
"size_t length_signature",
|
30
|
+
"int (*keypair)(uint8_t *pubKey, uint8_t* secretKey)",
|
31
|
+
"int (*sign)(uint8_t *signature, size_t signature_len, const uint8_t* message, size_t message_len, const unit8_t * secretKey)",
|
32
|
+
"int (*verify)(uint8_t *message, size_t message_len, const uint8_t* signature, size_t signature_len, const unit8_t * pubKey)"
|
33
|
+
]
|
34
|
+
|
35
|
+
end
|
data/lib/roqs/version.rb
ADDED
data/lib/roqs/wrapper.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
require 'fiddle'
|
3
|
+
|
4
|
+
module Roqs
|
5
|
+
module Wrapper
|
6
|
+
class WrapperError < StandardError; end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def load_oqs_lib
|
10
|
+
os = detect_os
|
11
|
+
logger.debug "Found OS #{os}"
|
12
|
+
load_arch_lib(os)
|
13
|
+
end
|
14
|
+
|
15
|
+
def detect_os
|
16
|
+
plat = RUBY_PLATFORM
|
17
|
+
if plat =~ /linux/
|
18
|
+
:linux
|
19
|
+
elsif plat =~ /darwin/
|
20
|
+
:macos
|
21
|
+
elsif plat =~ /mingw/
|
22
|
+
:windows
|
23
|
+
else
|
24
|
+
raise WrapperError, "Unknown platform detected. [#{plat}]"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_arch_lib(os)
|
29
|
+
plat = RUBY_PLATFORM
|
30
|
+
pplat = plat.split('-')[0]
|
31
|
+
logger.debug "OS architecture is #{pplat}"
|
32
|
+
usrDrvDir = ENV['ROQS_LIBOQS_DIR']
|
33
|
+
if not_empty?(usrDrvDir)
|
34
|
+
logger.debug "Load liboqs shared library from user provided root : #{File.join(usrDrvDir, pplat)}"
|
35
|
+
drvDir = File.join(usrDrvDir,pplat)
|
36
|
+
else
|
37
|
+
logger.debug "Load liboqs shared library from Roqs internal root : #{File.join(File.dirname(__FILE__),"..","..","native","#{os}",pplat)}"
|
38
|
+
drvDir = File.join(File.dirname(__FILE__),"..","..","native","#{os}",pplat)
|
39
|
+
end
|
40
|
+
|
41
|
+
if File.exist?(drvDir)
|
42
|
+
Dir.glob(File.join(drvDir,"liboqs*")) do |f|
|
43
|
+
logger.debug "Loading liboqs at : #{f}"
|
44
|
+
dlload f
|
45
|
+
end
|
46
|
+
else
|
47
|
+
errMsg = []
|
48
|
+
errMsg << "Shared library of liboqs (https://github.com/open-quantum-safe/liboqs) could not be found at '#{drvDir}'"
|
49
|
+
errMsg << "You might need to compile for your platform."
|
50
|
+
errMsg << "Simply follow the steps beflow:"
|
51
|
+
errMsg << "1. Clone the repository at https://github.com/open-quantum-safe/liboqs"
|
52
|
+
errMsg << " > clone https://github.com/open-quantum-safe/liboqs liboqs"
|
53
|
+
errMsg << "2. Make sure all pre-requisites are installed as documented here : https://github.com/open-quantum-safe/liboqs#quickstart"
|
54
|
+
errMsg << "3. Run the following commands: "
|
55
|
+
errMsg << " > cd liboqs && mkdir build && cd build"
|
56
|
+
errMsg << " > cmake -GNinja .. -DBUILD_SHARED_LIBS=ON"
|
57
|
+
errMsg << " > ninja"
|
58
|
+
errMsg << "4. Shared library shall be built under lib dir."
|
59
|
+
errMsg << "5. Copy the shared library into '#{drvDir}' and you should be good to go"
|
60
|
+
errMsg << " Note: System shall read env variable 'ROQS_LIBOQS_DIR' to decide where to load the liboqs dynamic library from."
|
61
|
+
errMsg << " If no value is given, system shall load from default path : #{File.join(File.dirname(__FILE__),"..","..","native","#{os}",pplat)}"
|
62
|
+
raise WrapperError, errMsg.join("\n")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def logger
|
67
|
+
Roqs.logger(:roqs_wrapper)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def self.included(klass)
|
71
|
+
klass.extend(ClassMethods)
|
72
|
+
end
|
73
|
+
|
74
|
+
def logger
|
75
|
+
self.class.logger
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/lib/roqs.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'teLogger'
|
4
|
+
require 'toolrack'
|
5
|
+
|
6
|
+
require_relative "roqs/version"
|
7
|
+
|
8
|
+
module Roqs
|
9
|
+
include TR::CondUtils
|
10
|
+
|
11
|
+
# OQS_STATUS
|
12
|
+
OQS_ERROR = -1
|
13
|
+
OQS_SUCCESS = 0
|
14
|
+
OQS_EXTERNAL_LIB_ERROR_OPENSSL = 50
|
15
|
+
|
16
|
+
class Error < StandardError; end
|
17
|
+
# Your code goes here...
|
18
|
+
|
19
|
+
def self.logger(tag = nil, &block)
|
20
|
+
@_logger = TeLogger::Tlogger.new if @_logger.nil?
|
21
|
+
|
22
|
+
if block
|
23
|
+
if not_empty?(tag)
|
24
|
+
@_logger.with_tag(tag, &block)
|
25
|
+
else
|
26
|
+
@_logger.with_tag(@_logger.tag, &block)
|
27
|
+
end
|
28
|
+
elsif is_empty?(tag)
|
29
|
+
@_logger.tag = :roqs
|
30
|
+
@_logger
|
31
|
+
else
|
32
|
+
# no block but tag is given? hmm
|
33
|
+
@_logger.tag = tag
|
34
|
+
@_logger
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
require_relative "roqs/struct"
|
41
|
+
require_relative "roqs/kem"
|
42
|
+
require_relative "roqs/sig"
|
Binary file
|
Binary file
|
Binary file
|
data/sig/roqs.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roqs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-11-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: teLogger
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: toolrack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.23'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.23'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: release-gem
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.3
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.3
|
55
|
+
description: ''
|
56
|
+
email:
|
57
|
+
- chris@antrapol.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".rspec"
|
63
|
+
- ".rubocop.yml"
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- TEST-RESULT.md
|
67
|
+
- lib/roqs.rb
|
68
|
+
- lib/roqs/common_wrapper.rb
|
69
|
+
- lib/roqs/kem.rb
|
70
|
+
- lib/roqs/kem_public_key.rb
|
71
|
+
- lib/roqs/kem_wrapper.rb
|
72
|
+
- lib/roqs/sig.rb
|
73
|
+
- lib/roqs/sig_wrapper.rb
|
74
|
+
- lib/roqs/struct.rb
|
75
|
+
- lib/roqs/version.rb
|
76
|
+
- lib/roqs/wrapper.rb
|
77
|
+
- native/linux/x86_64/liboqs.so.0.9.0
|
78
|
+
- native/macos/x86_64/liboqs.0.7.0.dylib
|
79
|
+
- native/windows/x64/liboqs.dll
|
80
|
+
- sig/roqs.rbs
|
81
|
+
homepage: ''
|
82
|
+
licenses: []
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.6.0
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubygems_version: 3.4.6
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: ''
|
103
|
+
test_files: []
|