roqs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|