ruby_clang_fpe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/python3
2
+
3
+ import subprocess
4
+ import re
5
+ import unittest
6
+
7
+ #
8
+ # format: radix, key, tweak, plainext, ciphertext
9
+ #
10
+
11
+ ff1 = [
12
+ # AES-128
13
+ [
14
+ 10,
15
+ "2B7E151628AED2A6ABF7158809CF4F3C",
16
+ "",
17
+ "0123456789",
18
+ "2433477484",
19
+ ],
20
+ [
21
+ 10,
22
+ "2B7E151628AED2A6ABF7158809CF4F3C",
23
+ "39383736353433323130",
24
+ "0123456789",
25
+ "6124200773",
26
+ ],
27
+ [
28
+ 36,
29
+ "2B7E151628AED2A6ABF7158809CF4F3C",
30
+ "3737373770717273373737",
31
+ "0123456789abcdefghi",
32
+ "a9tv40mll9kdu509eum",
33
+ ],
34
+
35
+ # AES-192
36
+ [
37
+ 10,
38
+ "2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F",
39
+ "",
40
+ "0123456789",
41
+ "2830668132",
42
+ ],
43
+ [
44
+ 10,
45
+ "2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F",
46
+ "39383736353433323130",
47
+ "0123456789",
48
+ "2496655549",
49
+ ],
50
+ [
51
+ 36,
52
+ "2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F",
53
+ "3737373770717273373737",
54
+ "0123456789abcdefghi",
55
+ "xbj3kv35jrawxv32ysr",
56
+ ],
57
+
58
+ # AES-256
59
+ [
60
+ 10,
61
+ "2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F7F036D6F04FC6A94",
62
+ "",
63
+ "0123456789",
64
+ "6657667009",
65
+ ],
66
+ [
67
+ 10,
68
+ "2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F7F036D6F04FC6A94",
69
+ "39383736353433323130",
70
+ "0123456789",
71
+ "1001623463",
72
+ ],
73
+ [
74
+ 36,
75
+ "2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F7F036D6F04FC6A94",
76
+ "3737373770717273373737",
77
+ "0123456789abcdefghi",
78
+ "xs8a0azh2avyalyzuwd",
79
+ ],
80
+ ]
81
+
82
+ ff3 = [
83
+ # AES-128
84
+ [
85
+ 10,
86
+ "EF4359D8D580AA4F7F036D6F04FC6A94",
87
+ "D8E7920AFA330A73",
88
+ "890121234567890000",
89
+ "750918814058654607",
90
+ ],
91
+ [
92
+ 10,
93
+ "EF4359D8D580AA4F7F036D6F04FC6A94",
94
+ "9A768A92F60E12D8",
95
+ "890121234567890000",
96
+ "018989839189395384",
97
+ ],
98
+ [
99
+ 10,
100
+ "EF4359D8D580AA4F7F036D6F04FC6A94",
101
+ "D8E7920AFA330A73",
102
+ "89012123456789000000789000000",
103
+ "48598367162252569629397416226",
104
+ ],
105
+ [
106
+ 10, "EF4359D8D580AA4F7F036D6F04FC6A94",
107
+ "0000000000000000",
108
+ "89012123456789000000789000000",
109
+ "34695224821734535122613701434",
110
+ ],
111
+ [
112
+ 26, "EF4359D8D580AA4F7F036D6F04FC6A94",
113
+ "9A768A92F60E12D8",
114
+ "0123456789abcdefghi",
115
+ "g2pk40i992fn20cjakb",
116
+ ],
117
+
118
+ # AES-192
119
+ [
120
+ 10,
121
+ "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6",
122
+ "D8E7920AFA330A73",
123
+ "890121234567890000",
124
+ "646965393875028755",
125
+ ],
126
+ [
127
+ 10,
128
+ "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6",
129
+ "9A768A92F60E12D8",
130
+ "890121234567890000",
131
+ "961610514491424446",
132
+ ],
133
+ [
134
+ 10,
135
+ "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6",
136
+ "D8E7920AFA330A73",
137
+ "89012123456789000000789000000",
138
+ "53048884065350204541786380807",
139
+ ],
140
+ [
141
+ 10, "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6",
142
+ "0000000000000000",
143
+ "89012123456789000000789000000",
144
+ "98083802678820389295041483512",
145
+ ],
146
+ [
147
+ 26, "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6",
148
+ "9A768A92F60E12D8",
149
+ "0123456789abcdefghi",
150
+ "i0ihe2jfj7a9opf9p88",
151
+ ],
152
+
153
+ # AES-256
154
+ [
155
+ 10,
156
+ "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C",
157
+ "D8E7920AFA330A73",
158
+ "890121234567890000",
159
+ "922011205562777495",
160
+ ],
161
+ [
162
+ 10,
163
+ "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C",
164
+ "9A768A92F60E12D8",
165
+ "890121234567890000",
166
+ "504149865578056140",
167
+ ],
168
+ [
169
+ 10,
170
+ "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C",
171
+ "D8E7920AFA330A73",
172
+ "89012123456789000000789000000",
173
+ "04344343235792599165734622699",
174
+ ],
175
+ [
176
+ 10, "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C",
177
+ "0000000000000000",
178
+ "89012123456789000000789000000",
179
+ "30859239999374053872365555822",
180
+ ],
181
+ [
182
+ 26, "EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C",
183
+ "9A768A92F60E12D8",
184
+ "0123456789abcdefghi",
185
+ "p0b2godfja9bhb7bk38",
186
+ ],
187
+ ]
188
+
189
+ # ACVP vectors for FF3-1 using 56-bit tweaks from private communication updating:
190
+ # https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#name-test-groups
191
+
192
+ testVectors_ACVP_AES_FF3_1 = [
193
+ # AES - 128
194
+ {
195
+ # tg: 1 tc: 1
196
+ "radix": 10,
197
+ "alphabet": "0123456789",
198
+ "key": "2DE79D232DF5585D68CE47882AE256D6",
199
+ "tweak": "CBD09280979564",
200
+ "plaintext": "3992520240",
201
+ "ciphertext": "8901801106"
202
+ },
203
+ {
204
+ # tg: 1 tc: 1
205
+ "radix": 10,
206
+ "alphabet": "0123456789",
207
+ "key": "01C63017111438F7FC8E24EB16C71AB5",
208
+ "tweak": "C4E822DCD09F27",
209
+ "plaintext": "60761757463116869318437658042297305934914824457484538562",
210
+ "ciphertext": "35637144092473838892796702739628394376915177448290847293"
211
+ },
212
+ # AES - 192
213
+ {
214
+ # tg: 4 tc: 76
215
+ "radix": 10,
216
+ "alphabet": "0123456789",
217
+ "key": "F62EDB777A671075D47563F3A1E9AC797AA706A2D8E02FC8",
218
+ "tweak": "493B8451BF6716",
219
+ "plaintext": "4406616808",
220
+ "ciphertext": "1807744762"
221
+ },
222
+ {
223
+ # tg: 4 tc: 77
224
+ "radix": 10,
225
+ "alphabet": "0123456789",
226
+ "key": "0951B475D1A327C52756F2624AF224C80E9BE85F09B2D44F",
227
+ "tweak": "D679E2EA3054E1",
228
+ "plaintext": "99980459818278359406199791971849884432821321826358606310",
229
+ "ciphertext": "84359031857952748660483617398396641079558152339419110919"
230
+ },
231
+ # AES - 256
232
+ {
233
+ # tg: 7 tc: 151
234
+ "radix": 10,
235
+ "alphabet": "0123456789",
236
+ "key": "1FAA03EFF55A06F8FAB3F1DC57127D493E2F8F5C365540467A3A055BDBE6481D",
237
+ "tweak": "4D67130C030445",
238
+ "plaintext": "3679409436",
239
+ "ciphertext": "1735794859"
240
+ },
241
+ {
242
+ # tg: 7 tc: 152
243
+ "radix": 10,
244
+ "alphabet": "0123456789",
245
+ "key": "9CE16E125BD422A011408EB083355E7089E70A4CD2F59E141D0B94A74BCC5967",
246
+ "tweak": "4684635BD2C821",
247
+ "plaintext": "85783290820098255530464619643265070052870796363685134012",
248
+ "ciphertext": "75104723514036464144839960480545848044718729603261409917"
249
+ },
250
+
251
+ ]
252
+
253
+ class TestFPE(unittest.TestCase):
254
+
255
+ def xest_vectors_ff1(self):
256
+ regexp = re.compile('(?<=ciphertext: )[a-zA-Z0-9]+')
257
+ for index, test in enumerate(ff1):
258
+ with self.subTest(index=index):
259
+ radix = test[0]
260
+ key = test[1]
261
+ tweak = test[2]
262
+ plain = test[3]
263
+ cipher = test[4]
264
+ p = subprocess.Popen(['./example', key, tweak, str(radix), plain], stdin = subprocess.PIPE, stdout = subprocess.PIPE)
265
+ output = p.communicate()[0]
266
+ results = regexp.findall(output.decode('utf-8'))[0]
267
+ p.wait()
268
+
269
+ #print(f'FF1 case #: {index}')
270
+ #print(f'plaintext: {plain}')
271
+ #print(f'ciphertext: {results}')
272
+ self.assertEqual(results, cipher)
273
+
274
+ def xest_vectors_ff3(self):
275
+ regexp = re.compile('(?<=ciphertext: )[a-zA-Z0-9]+')
276
+ for index, test in enumerate(ff3):
277
+ with self.subTest(index=index):
278
+ radix = test[0]
279
+ key = test[1]
280
+ tweak = test[2]
281
+ plain = test[3]
282
+ cipher = test[4]
283
+ p = subprocess.Popen(['./example', key, tweak, str(radix), plain], stdin = subprocess.PIPE, stdout = subprocess.PIPE)
284
+ output = p.communicate()[0]
285
+ results = regexp.findall(output.decode('utf-8'))[1]
286
+ p.wait()
287
+
288
+ #print(f'FF3 case #: {index}')
289
+ #print(f'plaintext: {plain}')
290
+ #print(f'ciphertext: {results}')
291
+ self.assertEqual(results, cipher)
292
+
293
+ def xest_encrypt_acvp(self):
294
+ regexp = re.compile('(?<=ciphertext: )[a-zA-Z0-9]+')
295
+ for testVector in testVectors_ACVP_AES_FF3_1:
296
+ with self.subTest(testVector=testVector):
297
+ p = subprocess.Popen(['./example', testVector['key'], testVector['tweak'], str(testVector['radix']), testVector['plaintext']], stdin = subprocess.PIPE, stdout = subprocess.PIPE)
298
+ output = p.communicate()[0]
299
+ results = regexp.findall(output.decode('utf-8'))[1]
300
+ p.wait()
301
+ self.assertEqual(results, testVector['ciphertext'])
302
+
303
+ def test_one(self):
304
+ print('starting')
305
+ cipher_regexp = re.compile('(?<=ciphertext: )[a-zA-Z0-9]+')
306
+ decrypt_regexp = re.compile('(?<=decrypted: )[a-zA-Z0-9]+')
307
+
308
+ radix = 10
309
+ key = "2B7E151628AED2A6ABF7158809CF4F3C"
310
+ tweak = ""
311
+ plain = "0123456789"
312
+ cipher = "2433477484"
313
+
314
+ p = subprocess.run(['./example', key, tweak, str(radix), plain], capture_output=True, text=True)
315
+ output = p.stdout
316
+ ciphertext = cipher_regexp.findall(output)[0]
317
+ decrypted = decrypt_regexp.findall(output)[0]
318
+ print(f'FF3 case #: 1')
319
+ print(f'plaintext: {plain}')
320
+ print(f'ciphertext: {ciphertext}')
321
+ print(f'decrypted: {decrypted}')
322
+ self.assertEqual(ciphertext, cipher)
323
+ self.assertEqual(decrypted, plain)
324
+
325
+ if __name__ == '__main__':
326
+ unittest.main()
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_clang_fpe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Luna
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-10-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry-doc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-rescue
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-stack_explorer
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Format-preserving encryption for Ruby, based on https://github.com/mysto/clang-fpe.
70
+ email:
71
+ - dancluna@gmail.com
72
+ executables: []
73
+ extensions:
74
+ - ext/ruby_clang_fpe/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".rubocop.yml"
78
+ - ".ruby-version"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - ext/ruby_clang_fpe/extconf.rb
86
+ - ext/ruby_clang_fpe/ruby_clang_fpe.c
87
+ - ext/ruby_clang_fpe/ruby_clang_fpe.h
88
+ - lib/ruby_clang_fpe.rb
89
+ - lib/ruby_clang_fpe/fpe_key.rb
90
+ - lib/ruby_clang_fpe/version.rb
91
+ - ruby_clang_fpe.gemspec
92
+ - sig/ruby_clang_fpe.rbs
93
+ - vendor/clang-fpe/.github/workflows/c-cpp.yml
94
+ - vendor/clang-fpe/.gitignore
95
+ - vendor/clang-fpe/.travis.yml
96
+ - vendor/clang-fpe/LICENSE
97
+ - vendor/clang-fpe/Makefile
98
+ - vendor/clang-fpe/README.md
99
+ - vendor/clang-fpe/configure
100
+ - vendor/clang-fpe/example.c
101
+ - vendor/clang-fpe/src/ff1.c
102
+ - vendor/clang-fpe/src/ff3.c
103
+ - vendor/clang-fpe/src/fpe.h
104
+ - vendor/clang-fpe/src/fpe_locl.c
105
+ - vendor/clang-fpe/src/fpe_locl.h
106
+ - vendor/clang-fpe/test.py
107
+ homepage: https://github.com/dcluna/ruby_clang_fpe
108
+ licenses:
109
+ - MIT
110
+ metadata:
111
+ allowed_push_host: https://rubygems.org
112
+ homepage_uri: https://github.com/dcluna/ruby_clang_fpe
113
+ source_code_uri: https://github.com/dcluna/ruby_clang_fpe
114
+ changelog_uri: https://github.com/dcluna/ruby_clang_fpe
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: 2.6.0
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubygems_version: 3.1.6
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Ruby bindings for the Clang FPE library.
134
+ test_files: []