ruby_clang_fpe 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/.rubocop.yml +13 -0
- data/.ruby-version +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +78 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +32 -0
- data/Rakefile +24 -0
- data/ext/ruby_clang_fpe/extconf.rb +34 -0
- data/ext/ruby_clang_fpe/ruby_clang_fpe.c +134 -0
- data/ext/ruby_clang_fpe/ruby_clang_fpe.h +6 -0
- data/lib/ruby_clang_fpe/fpe_key.rb +20 -0
- data/lib/ruby_clang_fpe/version.rb +5 -0
- data/lib/ruby_clang_fpe.rb +9 -0
- data/ruby_clang_fpe.gemspec +45 -0
- data/sig/ruby_clang_fpe.rbs +4 -0
- data/vendor/clang-fpe/.github/workflows/c-cpp.yml +22 -0
- data/vendor/clang-fpe/.gitignore +3 -0
- data/vendor/clang-fpe/.travis.yml +2 -0
- data/vendor/clang-fpe/LICENSE +21 -0
- data/vendor/clang-fpe/Makefile +60 -0
- data/vendor/clang-fpe/README.md +124 -0
- data/vendor/clang-fpe/configure +4 -0
- data/vendor/clang-fpe/example.c +59 -0
- data/vendor/clang-fpe/src/ff1.c +411 -0
- data/vendor/clang-fpe/src/ff3.c +334 -0
- data/vendor/clang-fpe/src/fpe.h +47 -0
- data/vendor/clang-fpe/src/fpe_locl.c +84 -0
- data/vendor/clang-fpe/src/fpe_locl.h +22 -0
- data/vendor/clang-fpe/test.py +326 -0
- metadata +134 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
[![Build Status](https://github.com/mysto/clang-fpe/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/mysto/clang-fpe/actions)
|
2
|
+
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
3
|
+
|
4
|
+
<p align="center">
|
5
|
+
<a href="https://privacylogistics.com/">
|
6
|
+
<img
|
7
|
+
alt="Mysto"
|
8
|
+
src="https://privacylogistics.com/Mysto-logo.jpg"
|
9
|
+
/>
|
10
|
+
</a>
|
11
|
+
</p>
|
12
|
+
|
13
|
+
# FPE - Format Preserving Encryption Implementation in C
|
14
|
+
|
15
|
+
An implementation of the NIST approved FF1, FF3 and FF3-1 Format Preserving Encryption (FPE) algorithms in Python.
|
16
|
+
|
17
|
+
This package implements the FPE algorithm for Format Preserving Encryption as described in the March 2016 NIST publication 800-38G _Methods for Format-Preserving Encryption_,
|
18
|
+
and revised on February 28th, 2019 with a draft update for FF3-1.
|
19
|
+
|
20
|
+
* [NIST Recommendation SP 800-38G (FF3)](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf)
|
21
|
+
* [NIST Recommendation SP 800-38G Revision 1 (FF3-1)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38Gr1-draft.pdf)
|
22
|
+
|
23
|
+
## Build and Run
|
24
|
+
|
25
|
+
To compile the example.c with the fpe library, just run
|
26
|
+
|
27
|
+
`make`
|
28
|
+
|
29
|
+
To build on macOS:
|
30
|
+
```shell
|
31
|
+
brew install openssl
|
32
|
+
export CFLAGS="-I$(brew --prefix openssl)/include"
|
33
|
+
export LDFLAGS="-L$(brew --prefix openssl)/lib"
|
34
|
+
```
|
35
|
+
Run the example in
|
36
|
+
[example.c](https://github.com/0NG/Format-Preserving-Encryption/blob/master/example.c).
|
37
|
+
|
38
|
+
```shell
|
39
|
+
./example EF4359D8D580AA4F7F036D6F04FC6A94 D8E7920AFA330A73 10 890121234567890000
|
40
|
+
|
41
|
+
plaintext: 890121234567890000
|
42
|
+
|
43
|
+
FF1 ciphertext: 318181603547192051
|
44
|
+
FF1 decrypted: 890121234567890000
|
45
|
+
|
46
|
+
FF3 ciphertext: 750918814058654607
|
47
|
+
FF3 decrypted: 890121234567890000
|
48
|
+
```
|
49
|
+
Run the tests
|
50
|
+
|
51
|
+
There are official [test vectors](http://csrc.nist.gov/groups/ST/toolkit/examples.html) for both FF1 and FF3 provided by NIST. You can run [test.py](https://github.com/0NG/Format-Preserving-Encryption/blob/master/test.py) with python 3.x.
|
52
|
+
with a known test vector:
|
53
|
+
|
54
|
+
```shell
|
55
|
+
make test
|
56
|
+
```
|
57
|
+
## Example Usage
|
58
|
+
|
59
|
+
This implementation is based on OpenSSL's BIGNUM and AES, so you need to install OpenSSL first.
|
60
|
+
|
61
|
+
There are several functions for FF1 and FF3 algorithm, respectively.
|
62
|
+
|
63
|
+
1. Create and delete FF1 key and tweak
|
64
|
+
|
65
|
+
```c
|
66
|
+
FPE_KEY* FPE_ff1_create_key(const char *key, const char *tweak, const unsigned int radix);
|
67
|
+
|
68
|
+
void FPE_ff1_delete_key(FPE_KEY *keystruct);
|
69
|
+
```
|
70
|
+
|
71
|
+
| name | description |
|
72
|
+
| -------- | ---------------------------------------- |
|
73
|
+
| key | encryption key (128 bit, 192 bits or 256 bits), represented as a c string |
|
74
|
+
| tweak | tweak, represented as a c string |
|
75
|
+
| radix | number of characters in the given alphabet, it must be in [2, 2^16] |
|
76
|
+
| returns | FPE_KEY structure |
|
77
|
+
|
78
|
+
2. encrypt or decrypt text using FF1 algorithm
|
79
|
+
|
80
|
+
```c
|
81
|
+
void FPE_ff1_encrypt(char *plaintext, char *ciphertext, FPE_KEY *keystruct)
|
82
|
+
void FPE_ff1_decrypt(char *ciphertext, char *plaintext, FPE_KEY *keystruct)
|
83
|
+
```
|
84
|
+
|
85
|
+
| name | description |
|
86
|
+
| ----- | ---------------------------------------- |
|
87
|
+
| plaintext | numeral string to be encrypted, represented as an array of integers |
|
88
|
+
| ciphertext | encrypted numeral string, represented as an array of integers |
|
89
|
+
| keystruct | FPE_KEY structure that has been set with key and tweak |
|
90
|
+
|
91
|
+
3. Create and delete FF3 key and tweak
|
92
|
+
|
93
|
+
```c
|
94
|
+
FPE_KEY* FPE_ff3_create_key(const char *key, const char *tweak, const unsigned char radix);
|
95
|
+
FPE_KEY* FPE_ff3_1_create_key(const char *key, const char *tweak, const unsigned char radix);
|
96
|
+
|
97
|
+
void FPE_ff3_delete_key(FPE_KEY *keystruct);
|
98
|
+
```
|
99
|
+
|
100
|
+
| name | description |
|
101
|
+
| ------- | ---------------------------------------- |
|
102
|
+
| key | encryption key (128 bit, 192 bits or 256 bits), represented as a c string |
|
103
|
+
| tweak | tweak, represented as a c string (it must be 64 bytes) |
|
104
|
+
| radix | number of characters in the given alphabet, it must be in [2, 2^16] |
|
105
|
+
| returns | FPE_KEY structure |
|
106
|
+
|
107
|
+
4. encrypt or decrypt text using FF3 algorithm
|
108
|
+
|
109
|
+
```c
|
110
|
+
void FPE_ff3_encrypt(char *plaintext, char *ciphertext, FPE_KEY *keystruct);
|
111
|
+
void FPE_ff3_decrypt(char *ciphertext, char *plaintext, FPE_KEY *keystruct);
|
112
|
+
```
|
113
|
+
|
114
|
+
| name | description |
|
115
|
+
| ----- | ---------------------------------------- |
|
116
|
+
| plaintext | numeral string to be encrypted, represented as an array of integers |
|
117
|
+
| ciphertext | encrypted numeral string, represented as an array of integers |
|
118
|
+
| radix | number of characters in the given alphabet, it must be in [2, 2^16] |
|
119
|
+
| keystruct | FPE_KEY structure that has been set with key and tweak |
|
120
|
+
|
121
|
+
## TODO
|
122
|
+
|
123
|
+
1. Performance testing
|
124
|
+
3. Custom alphabet support
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <assert.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <fpe.h>
|
6
|
+
#include <fpe_locl.h>
|
7
|
+
|
8
|
+
/*
|
9
|
+
usage:
|
10
|
+
|
11
|
+
./example 2DE79D232DF5585D68CE47882AE256D6 CBD09280979564 10 3992520240
|
12
|
+
|
13
|
+
*/
|
14
|
+
|
15
|
+
int main(int argc, char *argv[])
|
16
|
+
{
|
17
|
+
if (argc != 5) {
|
18
|
+
printf("Usage: %s <key> <tweak> <radix> <plaintext>\n", argv[0]);
|
19
|
+
return 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
char ciphertext[100];
|
23
|
+
char resulttext[100];
|
24
|
+
|
25
|
+
char* key = argv[1];
|
26
|
+
char* tweak = argv[2];
|
27
|
+
char* plaintext = argv[4];
|
28
|
+
int radix = atoi(argv[3]);
|
29
|
+
|
30
|
+
int txtlen = strlen(plaintext),
|
31
|
+
tlen = strlen(tweak) / 2;
|
32
|
+
|
33
|
+
FPE_KEY *ff1 = FPE_ff1_create_key(key, tweak, radix);
|
34
|
+
FPE_KEY *ff3 = (tlen == 7) ?
|
35
|
+
FPE_ff3_1_create_key(key, tweak, radix) :
|
36
|
+
FPE_ff3_create_key(key, tweak, radix);
|
37
|
+
|
38
|
+
//for (int i = 0; i < xlen; ++i)
|
39
|
+
// assert(x[i] < radix);
|
40
|
+
|
41
|
+
FPE_ff1_encrypt(plaintext, ciphertext, ff1);
|
42
|
+
printf("FF1 ciphertext: %s\n", ciphertext);
|
43
|
+
|
44
|
+
memset(resulttext, 0, txtlen);
|
45
|
+
FPE_ff1_decrypt(ciphertext, resulttext, ff1);
|
46
|
+
printf("FF1 decrypted: %s\n\n", resulttext);
|
47
|
+
|
48
|
+
FPE_ff3_encrypt(plaintext, ciphertext, ff3);
|
49
|
+
printf("FF3 ciphertext: %s\n", ciphertext);
|
50
|
+
|
51
|
+
memset(resulttext, 0, txtlen);
|
52
|
+
FPE_ff3_decrypt(ciphertext, resulttext, ff3);
|
53
|
+
printf("FF3 decrypted: %s\n\n", resulttext);
|
54
|
+
|
55
|
+
FPE_ff1_delete_key(ff1);
|
56
|
+
FPE_ff3_delete_key(ff3);
|
57
|
+
|
58
|
+
return 0;
|
59
|
+
}
|
@@ -0,0 +1,411 @@
|
|
1
|
+
#include <stdint.h>
|
2
|
+
#include <string.h>
|
3
|
+
#include <math.h>
|
4
|
+
#include <assert.h>
|
5
|
+
#include <openssl/aes.h>
|
6
|
+
#include <openssl/crypto.h>
|
7
|
+
#include <openssl/bn.h>
|
8
|
+
#include "fpe.h"
|
9
|
+
#include "fpe_locl.h"
|
10
|
+
|
11
|
+
// convert numeral string to number
|
12
|
+
void str2num(BIGNUM *Y, const unsigned int *X, unsigned long long radix, unsigned int len, BN_CTX *ctx)
|
13
|
+
{
|
14
|
+
BN_CTX_start(ctx);
|
15
|
+
BIGNUM *r = BN_CTX_get(ctx),
|
16
|
+
*x = BN_CTX_get(ctx);
|
17
|
+
|
18
|
+
BN_set_word(Y, 0);
|
19
|
+
BN_set_word(r, radix);
|
20
|
+
for (int i = 0; i < len; ++i) {
|
21
|
+
// Y = Y * radix + X[i]
|
22
|
+
BN_set_word(x, X[i]);
|
23
|
+
BN_mul(Y, Y, r, ctx);
|
24
|
+
BN_add(Y, Y, x);
|
25
|
+
}
|
26
|
+
|
27
|
+
BN_CTX_end(ctx);
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
|
31
|
+
// convert number to numeral string
|
32
|
+
void num2str(const BIGNUM *X, unsigned int *Y, unsigned int radix, int len, BN_CTX *ctx)
|
33
|
+
{
|
34
|
+
BN_CTX_start(ctx);
|
35
|
+
BIGNUM *dv = BN_CTX_get(ctx),
|
36
|
+
*rem = BN_CTX_get(ctx),
|
37
|
+
*r = BN_CTX_get(ctx),
|
38
|
+
*XX = BN_CTX_get(ctx);
|
39
|
+
|
40
|
+
BN_copy(XX, X);
|
41
|
+
BN_set_word(r, radix);
|
42
|
+
memset(Y, 0, len << 2);
|
43
|
+
|
44
|
+
for (int i = len - 1; i >= 0; --i) {
|
45
|
+
// XX / r = dv ... rem
|
46
|
+
BN_div(dv, rem, XX, r, ctx);
|
47
|
+
// Y[i] = XX % r
|
48
|
+
Y[i] = BN_get_word(rem);
|
49
|
+
// XX = XX / r
|
50
|
+
BN_copy(XX, dv);
|
51
|
+
}
|
52
|
+
|
53
|
+
BN_CTX_end(ctx);
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
|
57
|
+
void FF1_encrypt(const unsigned int *plaintext, unsigned int *ciphertext, FPE_KEY *key, const unsigned char *tweak, size_t txtlen, size_t tweaklen)
|
58
|
+
{
|
59
|
+
BIGNUM *bnum = BN_new(),
|
60
|
+
*y = BN_new(),
|
61
|
+
*c = BN_new(),
|
62
|
+
*anum = BN_new(),
|
63
|
+
*qpow_u = BN_new(),
|
64
|
+
*qpow_v = BN_new();
|
65
|
+
BN_CTX *ctx = BN_CTX_new();
|
66
|
+
|
67
|
+
union {
|
68
|
+
long one;
|
69
|
+
char little;
|
70
|
+
} is_endian = { 1 };
|
71
|
+
|
72
|
+
// Calculate split point
|
73
|
+
int u = floor2(txtlen, 1);
|
74
|
+
int v = txtlen - u;
|
75
|
+
|
76
|
+
// Split the message
|
77
|
+
memcpy(ciphertext, plaintext, txtlen << 2);
|
78
|
+
unsigned int *A = ciphertext;
|
79
|
+
unsigned int *B = ciphertext + u;
|
80
|
+
|
81
|
+
pow_uv(qpow_u, qpow_v, key->radix, u, v, ctx);
|
82
|
+
|
83
|
+
unsigned int temp = (unsigned int)ceil(v * log2(key->radix));
|
84
|
+
const int b = ceil2(temp, 3);
|
85
|
+
const int d = 4 * ceil2(b, 2) + 4;
|
86
|
+
|
87
|
+
int pad = ( (-tweaklen - b - 1) % 16 + 16 ) % 16;
|
88
|
+
int Qlen = tweaklen + pad + 1 + b;
|
89
|
+
unsigned char P[16];
|
90
|
+
unsigned char *Q = (unsigned char *)OPENSSL_malloc(Qlen), *Bytes = (unsigned char *)OPENSSL_malloc(b);
|
91
|
+
|
92
|
+
// initialize P
|
93
|
+
P[0] = 0x1;
|
94
|
+
P[1] = 0x2;
|
95
|
+
P[2] = 0x1;
|
96
|
+
P[7] = u % 256;
|
97
|
+
if (is_endian.little) {
|
98
|
+
temp = (key->radix << 8) | 10;
|
99
|
+
P[3] = (temp >> 24) & 0xff;
|
100
|
+
P[4] = (temp >> 16) & 0xff;
|
101
|
+
P[5] = (temp >> 8) & 0xff;
|
102
|
+
P[6] = temp & 0xff;
|
103
|
+
P[8] = (txtlen >> 24) & 0xff;
|
104
|
+
P[9] = (txtlen >> 16) & 0xff;
|
105
|
+
P[10] = (txtlen >> 8) & 0xff;
|
106
|
+
P[11] = txtlen & 0xff;
|
107
|
+
P[12] = (tweaklen >> 24) & 0xff;
|
108
|
+
P[13] = (tweaklen >> 16) & 0xff;
|
109
|
+
P[14] = (tweaklen >> 8) & 0xff;
|
110
|
+
P[15] = tweaklen & 0xff;
|
111
|
+
} else {
|
112
|
+
*( (unsigned int *)(P + 3) ) = (key->radix << 8) | 10;
|
113
|
+
*( (unsigned int *)(P + 8) ) = txtlen;
|
114
|
+
*( (unsigned int *)(P + 12) ) = tweaklen;
|
115
|
+
}
|
116
|
+
|
117
|
+
// initialize Q
|
118
|
+
memcpy(Q, tweak, tweaklen);
|
119
|
+
memset(Q + tweaklen, 0x00, pad);
|
120
|
+
assert(tweaklen + pad - 1 <= Qlen);
|
121
|
+
|
122
|
+
unsigned char R[16];
|
123
|
+
int cnt = ceil2(d, 4) - 1;
|
124
|
+
int Slen = 16 + cnt * 16;
|
125
|
+
unsigned char *S = (unsigned char *)OPENSSL_malloc(Slen);
|
126
|
+
for (int i = 0; i < FF1_ROUNDS; ++i) {
|
127
|
+
// v
|
128
|
+
int m = (i & 1)? v: u;
|
129
|
+
|
130
|
+
// i
|
131
|
+
Q[tweaklen + pad] = i & 0xff;
|
132
|
+
str2num(bnum, B, key->radix, txtlen - m, ctx);
|
133
|
+
int BytesLen = BN_bn2bin(bnum, Bytes);
|
134
|
+
memset(Q + Qlen - b, 0x00, b);
|
135
|
+
|
136
|
+
int qtmp = Qlen - BytesLen;
|
137
|
+
memcpy(Q + qtmp, Bytes, BytesLen);
|
138
|
+
|
139
|
+
// ii PRF(P || Q), P is always 16 bytes long
|
140
|
+
AES_encrypt(P, R, &key->aes_enc_ctx);
|
141
|
+
int count = Qlen / 16;
|
142
|
+
unsigned char Ri[16];
|
143
|
+
unsigned char *Qi = Q;
|
144
|
+
for (int cc = 0; cc < count; ++cc) {
|
145
|
+
for (int j = 0; j < 16; ++j) Ri[j] = Qi[j] ^ R[j];
|
146
|
+
AES_encrypt(Ri, R, &key->aes_enc_ctx);
|
147
|
+
Qi += 16;
|
148
|
+
}
|
149
|
+
|
150
|
+
// iii
|
151
|
+
unsigned char tmp[16], SS[16];
|
152
|
+
memset(S, 0x00, Slen);
|
153
|
+
assert(Slen >= 16);
|
154
|
+
memcpy(S, R, 16);
|
155
|
+
for (int j = 1; j <= cnt; ++j) {
|
156
|
+
memset(tmp, 0x00, 16);
|
157
|
+
|
158
|
+
if (is_endian.little) {
|
159
|
+
// convert to big endian
|
160
|
+
// full unroll
|
161
|
+
tmp[15] = j & 0xff;
|
162
|
+
tmp[14] = (j >> 8) & 0xff;
|
163
|
+
tmp[13] = (j >> 16) & 0xff;
|
164
|
+
tmp[12] = (j >> 24) & 0xff;
|
165
|
+
} else *( (unsigned int *)tmp + 3 ) = j;
|
166
|
+
|
167
|
+
for (int k = 0; k < 16; ++k) tmp[k] ^= R[k];
|
168
|
+
AES_encrypt(tmp, SS, &key->aes_enc_ctx);
|
169
|
+
assert((S + 16 * j)[0] == 0x00);
|
170
|
+
assert(16 + 16 * j <= Slen);
|
171
|
+
memcpy(S + 16 * j, SS, 16);
|
172
|
+
}
|
173
|
+
|
174
|
+
// iv
|
175
|
+
BN_bin2bn(S, d, y);
|
176
|
+
// vi
|
177
|
+
// (num(A, key->radix, m) + y) % qpow(key->radix, m);
|
178
|
+
str2num(anum, A, key->radix, m, ctx);
|
179
|
+
// anum = (anum + y) mod qpow_uv
|
180
|
+
if (m == u) BN_mod_add(c, anum, y, qpow_u, ctx);
|
181
|
+
else BN_mod_add(c, anum, y, qpow_v, ctx);
|
182
|
+
|
183
|
+
// swap A and B
|
184
|
+
assert(A != B);
|
185
|
+
A = (unsigned int *)( (uintptr_t)A ^ (uintptr_t)B );
|
186
|
+
B = (unsigned int *)( (uintptr_t)B ^ (uintptr_t)A );
|
187
|
+
A = (unsigned int *)( (uintptr_t)A ^ (uintptr_t)B );
|
188
|
+
num2str(c, B, key->radix, m, ctx);
|
189
|
+
}
|
190
|
+
|
191
|
+
// free the space
|
192
|
+
BN_clear_free(anum);
|
193
|
+
BN_clear_free(bnum);
|
194
|
+
BN_clear_free(c);
|
195
|
+
BN_clear_free(y);
|
196
|
+
BN_clear_free(qpow_u);
|
197
|
+
BN_clear_free(qpow_v);
|
198
|
+
BN_CTX_free(ctx);
|
199
|
+
OPENSSL_free(Bytes);
|
200
|
+
OPENSSL_free(Q);
|
201
|
+
OPENSSL_free(S);
|
202
|
+
return;
|
203
|
+
}
|
204
|
+
|
205
|
+
void FF1_decrypt(const unsigned int *ciphertext, unsigned int *plaintext, FPE_KEY *key, const unsigned char *tweak, size_t txtlen, size_t tweaklen)
|
206
|
+
{
|
207
|
+
BIGNUM *bnum = BN_new(),
|
208
|
+
*y = BN_new(),
|
209
|
+
*c = BN_new(),
|
210
|
+
*anum = BN_new(),
|
211
|
+
*qpow_u = BN_new(),
|
212
|
+
*qpow_v = BN_new();
|
213
|
+
BN_CTX *ctx = BN_CTX_new();
|
214
|
+
|
215
|
+
union {
|
216
|
+
long one;
|
217
|
+
char little;
|
218
|
+
} is_endian = { 1 };
|
219
|
+
|
220
|
+
// Calculate split point
|
221
|
+
int u = floor2(txtlen, 1);
|
222
|
+
int v = txtlen - u;
|
223
|
+
|
224
|
+
// Split the message
|
225
|
+
memcpy(plaintext, ciphertext, txtlen << 2);
|
226
|
+
unsigned int *A = plaintext, *B = plaintext + u;
|
227
|
+
pow_uv(qpow_u, qpow_v, key->radix, u, v, ctx);
|
228
|
+
|
229
|
+
unsigned int temp = (unsigned int)ceil(v * log2(key->radix));
|
230
|
+
const int b = ceil2(temp, 3);
|
231
|
+
const int d = 4 * ceil2(b, 2) + 4;
|
232
|
+
|
233
|
+
int pad = ( (-tweaklen - b - 1) % 16 + 16 ) % 16;
|
234
|
+
int Qlen = tweaklen + pad + 1 + b;
|
235
|
+
unsigned char P[16];
|
236
|
+
unsigned char *Q = (unsigned char *)OPENSSL_malloc(Qlen), *Bytes = (unsigned char *)OPENSSL_malloc(b);
|
237
|
+
// initialize P
|
238
|
+
P[0] = 0x1;
|
239
|
+
P[1] = 0x2;
|
240
|
+
P[2] = 0x1;
|
241
|
+
P[7] = u % 256;
|
242
|
+
if (is_endian.little) {
|
243
|
+
temp = (key->radix << 8) | 10;
|
244
|
+
P[3] = (temp >> 24) & 0xff;
|
245
|
+
P[4] = (temp >> 16) & 0xff;
|
246
|
+
P[5] = (temp >> 8) & 0xff;
|
247
|
+
P[6] = temp & 0xff;
|
248
|
+
P[8] = (txtlen >> 24) & 0xff;
|
249
|
+
P[9] = (txtlen >> 16) & 0xff;
|
250
|
+
P[10] = (txtlen >> 8) & 0xff;
|
251
|
+
P[11] = txtlen & 0xff;
|
252
|
+
P[12] = (tweaklen >> 24) & 0xff;
|
253
|
+
P[13] = (tweaklen >> 16) & 0xff;
|
254
|
+
P[14] = (tweaklen >> 8) & 0xff;
|
255
|
+
P[15] = tweaklen & 0xff;
|
256
|
+
} else {
|
257
|
+
*( (unsigned int *)(P + 3) ) = (key->radix << 8) | 10;
|
258
|
+
*( (unsigned int *)(P + 8) ) = txtlen;
|
259
|
+
*( (unsigned int *)(P + 12) ) = tweaklen;
|
260
|
+
}
|
261
|
+
|
262
|
+
// initialize Q
|
263
|
+
memcpy(Q, tweak, tweaklen);
|
264
|
+
memset(Q + tweaklen, 0x00, pad);
|
265
|
+
assert(tweaklen + pad - 1 <= Qlen);
|
266
|
+
|
267
|
+
unsigned char R[16];
|
268
|
+
int cnt = ceil2(d, 4) - 1;
|
269
|
+
int Slen = 16 + cnt * 16;
|
270
|
+
unsigned char *S = (unsigned char *)OPENSSL_malloc(Slen);
|
271
|
+
for (int i = FF1_ROUNDS - 1; i >= 0; --i) {
|
272
|
+
// v
|
273
|
+
int m = (i & 1)? v: u;
|
274
|
+
|
275
|
+
// i
|
276
|
+
Q[tweaklen + pad] = i & 0xff;
|
277
|
+
str2num(anum, A, key->radix, txtlen - m, ctx);
|
278
|
+
memset(Q + Qlen - b, 0x00, b);
|
279
|
+
int BytesLen = BN_bn2bin(anum, Bytes);
|
280
|
+
int qtmp = Qlen - BytesLen;
|
281
|
+
memcpy(Q + qtmp, Bytes, BytesLen);
|
282
|
+
|
283
|
+
// ii PRF(P || Q)
|
284
|
+
memset(R, 0x00, sizeof(R));
|
285
|
+
AES_encrypt(P, R, &key->aes_enc_ctx);
|
286
|
+
int count = Qlen / 16;
|
287
|
+
unsigned char Ri[16];
|
288
|
+
unsigned char *Qi = Q;
|
289
|
+
for (int cc = 0; cc < count; ++cc) {
|
290
|
+
for (int j = 0; j < 16; ++j) Ri[j] = Qi[j] ^ R[j];
|
291
|
+
AES_encrypt(Ri, R, &key->aes_enc_ctx);
|
292
|
+
Qi += 16;
|
293
|
+
}
|
294
|
+
|
295
|
+
// iii
|
296
|
+
unsigned char tmp[16], SS[16];
|
297
|
+
memset(S, 0x00, Slen);
|
298
|
+
memcpy(S, R, 16);
|
299
|
+
for (int j = 1; j <= cnt; ++j) {
|
300
|
+
memset(tmp, 0x00, 16);
|
301
|
+
|
302
|
+
if (is_endian.little) {
|
303
|
+
// convert to big endian
|
304
|
+
// full unroll
|
305
|
+
tmp[15] = j & 0xff;
|
306
|
+
tmp[14] = (j >> 8) & 0xff;
|
307
|
+
tmp[13] = (j >> 16) & 0xff;
|
308
|
+
tmp[12] = (j >> 24) & 0xff;
|
309
|
+
} else *( (unsigned int *)tmp + 3 ) = j;
|
310
|
+
|
311
|
+
for (int k = 0; k < 16; ++k) tmp[k] ^= R[k];
|
312
|
+
AES_encrypt(tmp, SS, &key->aes_enc_ctx);
|
313
|
+
assert((S + 16 * j)[0] == 0x00);
|
314
|
+
memcpy(S + 16 * j, SS, 16);
|
315
|
+
}
|
316
|
+
|
317
|
+
// iv
|
318
|
+
BN_bin2bn(S, d, y);
|
319
|
+
// vi
|
320
|
+
// (num(B, key->radix, m) - y) % qpow(key->radix, m);
|
321
|
+
str2num(bnum, B, key->radix, m, ctx);
|
322
|
+
if (m == u) BN_mod_sub(c, bnum, y, qpow_u, ctx);
|
323
|
+
else BN_mod_sub(c, bnum, y, qpow_v, ctx);
|
324
|
+
|
325
|
+
// swap A and B
|
326
|
+
assert(A != B);
|
327
|
+
A = (unsigned int *)( (uintptr_t)A ^ (uintptr_t)B );
|
328
|
+
B = (unsigned int *)( (uintptr_t)B ^ (uintptr_t)A );
|
329
|
+
A = (unsigned int *)( (uintptr_t)A ^ (uintptr_t)B );
|
330
|
+
num2str(c, A, key->radix, m, ctx);
|
331
|
+
|
332
|
+
}
|
333
|
+
|
334
|
+
// free the space
|
335
|
+
BN_clear_free(anum);
|
336
|
+
BN_clear_free(bnum);
|
337
|
+
BN_clear_free(y);
|
338
|
+
BN_clear_free(c);
|
339
|
+
BN_clear_free(qpow_u);
|
340
|
+
BN_clear_free(qpow_v);
|
341
|
+
BN_CTX_free(ctx);
|
342
|
+
OPENSSL_free(Bytes);
|
343
|
+
OPENSSL_free(Q);
|
344
|
+
OPENSSL_free(S);
|
345
|
+
return;
|
346
|
+
}
|
347
|
+
|
348
|
+
int create_ff1_key(const unsigned char *userKey, const int bits, const unsigned char *tweak, const unsigned int tweaklen, const unsigned int radix, FPE_KEY *key)
|
349
|
+
{
|
350
|
+
int ret;
|
351
|
+
if (bits != 128 && bits != 192 && bits != 256) {
|
352
|
+
ret = -1;
|
353
|
+
return ret;
|
354
|
+
}
|
355
|
+
key->tweaklen = tweaklen;
|
356
|
+
key->tweak = (unsigned char *)OPENSSL_malloc(tweaklen);
|
357
|
+
memcpy(key->tweak, tweak, tweaklen);
|
358
|
+
ret = AES_set_encrypt_key(userKey, bits, &key->aes_enc_ctx);
|
359
|
+
key->radix = radix;
|
360
|
+
return ret;
|
361
|
+
}
|
362
|
+
|
363
|
+
FPE_KEY* FPE_ff1_create_key(const char *key, const char *tweak, unsigned int radix)
|
364
|
+
{
|
365
|
+
unsigned char k[100],
|
366
|
+
t[100];
|
367
|
+
int klen = strlen(key) / 2;
|
368
|
+
int tlen = strlen(tweak) / 2;
|
369
|
+
|
370
|
+
hex2chars(key, k);
|
371
|
+
hex2chars(tweak, t);
|
372
|
+
|
373
|
+
FPE_KEY *keystruct = (FPE_KEY *)OPENSSL_malloc(sizeof(FPE_KEY));
|
374
|
+
create_ff1_key(k,klen*8,t,tlen,radix,keystruct);
|
375
|
+
return keystruct;
|
376
|
+
}
|
377
|
+
|
378
|
+
void FPE_ff1_delete_key(FPE_KEY *key)
|
379
|
+
{
|
380
|
+
OPENSSL_clear_free(key->tweak,key->tweaklen/8);
|
381
|
+
OPENSSL_clear_free(key,sizeof(key));
|
382
|
+
}
|
383
|
+
|
384
|
+
void FPE_ff1_encrypt(char *plaintext, char *ciphertext, FPE_KEY *key)
|
385
|
+
{
|
386
|
+
int txtlen = strlen(plaintext);
|
387
|
+
unsigned int x[100],
|
388
|
+
y[txtlen];
|
389
|
+
map_chars(plaintext, x);
|
390
|
+
|
391
|
+
printf("plaintext: ");
|
392
|
+
for (int i = 0; i < txtlen; ++i) printf("%d", x[i]);
|
393
|
+
printf("\n\n");
|
394
|
+
|
395
|
+
FF1_encrypt(x, y, key, key->tweak, txtlen, key->tweaklen);
|
396
|
+
|
397
|
+
inverse_map_chars(y, ciphertext, txtlen);
|
398
|
+
}
|
399
|
+
|
400
|
+
void FPE_ff1_decrypt(char *ciphertext, char* plaintext, FPE_KEY *key)
|
401
|
+
{
|
402
|
+
int txtlen = strlen(ciphertext);
|
403
|
+
unsigned int x[100],
|
404
|
+
y[txtlen];
|
405
|
+
map_chars(ciphertext, x);
|
406
|
+
|
407
|
+
FF1_decrypt(x, y, key, key->tweak, txtlen, key->tweaklen);
|
408
|
+
|
409
|
+
inverse_map_chars(y, plaintext, txtlen);
|
410
|
+
}
|
411
|
+
|