-
Notifications
You must be signed in to change notification settings - Fork 0
/
libssl-crypt.red
226 lines (200 loc) · 4.36 KB
/
libssl-crypt.red
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
Red [
File: %libssl-crypt.red
Author: "loziniak"
License: BSD-3
]
; clone https://github.com/loziniak/eth-wallet
#include %eth-wallet/pbkdf2.red
#system [
#switch OS [
Windows [
#define LIBCRYPTO-file "libcrypto-1_1.dll"
]
macOS [
#define LIBCRYPTO-file "libcrypto.dylib"
]
Linux [
#define LIBCRYPTO-file "libcrypto.so"
]
]
#import [
LIBCRYPTO-file cdecl [
EVP_CIPHER_CTX_new: "EVP_CIPHER_CTX_new" [
return: [int-ptr!]
]
EVP_CIPHER_CTX_free: "EVP_CIPHER_CTX_free" [
ctx [int-ptr!]
]
EVP_aes_256_cbc: "EVP_aes_256_cbc" [ ; 256-bit-key AES in CBC mode
return: [int-ptr!]
]
EVP_CipherInit_ex: "EVP_CipherInit_ex" [
ctx [int-ptr!]
type [int-ptr!]
engine [int-ptr!]
key [byte-ptr!]
iv [byte-ptr!]
enc [integer!]
return: [integer!]
]
EVP_CipherUpdate: "EVP_CipherUpdate" [
ctx [int-ptr!]
out [byte-ptr!]
outlen [int-ptr!]
in [byte-ptr!]
inlen [integer!]
return: [integer!]
]
EVP_CipherFinal_ex: "EVP_CipherFinal_ex" [
ctx [int-ptr!]
out [byte-ptr!]
outlen [int-ptr!]
return: [integer!]
]
ERR_get_error: "ERR_get_error" [
return: [integer!]
]
ERR_error_string: "ERR_error_string" [
e [integer!]
buf [byte-ptr!]
return: [c-string!]
]
]
]
fire-error: func [
msg [c-string!]
/local
s [red-string!]
] [
s: string/load "Libssl-crypt error. " 20 UTF-8
string/concatenate
s
string/load msg length? msg UTF-8
-1 0 yes no
fire [TO_ERROR(user message) s]
]
handle-error: func [
res [integer!]
ctx [int-ptr!]
] [
if 1 <> res [
if ctx <> null [EVP_CIPHER_CTX_free(ctx)]
fire-error ERR_error_string ERR_get_error null
]
]
binary-bytes: func [
bin [red-binary!]
return: [byte-ptr!]
/local bin-series [series-buffer!]
] [
bin-series: GET_BUFFER(bin)
(as byte-ptr! bin-series/offset) + bin/head
]
crypt-process: func [
in [red-binary!]
key [red-binary!]
iv [red-binary!]
type [int-ptr!]
encrypt? [logic!]
/local
ctx
in-series in-bytes inlen
key-series key-bytes iv-series iv-bytes
buffer max-chunk chunk
out outlen
] [
ctx: EVP_CIPHER_CTX_new
if ctx = null [
fire-error ERR_error_string ERR_get_error null
]
in-bytes: binary-bytes in
inlen: binary/rs-length? in
unless 32 = binary/rs-length? key [ ;-- AES256 key size, 32 bytes = 256 bits
fire-error "AES256 needs 256 bit key."
]
key-bytes: binary-bytes key
unless 16 = binary/rs-length? iv [ ;-- AES block size, 16 bytes = 128 bits
fire-error "AES needs 128 bit iv, equal to AES block size."
]
iv-bytes: binary-bytes iv
handle-error
EVP_CipherInit_ex ctx type null key-bytes iv-bytes as integer! encrypt?
ctx
max-chunk: 1024 ;-- 1 KiB
buffer: allocate max-chunk + 16 ;-- with additional padding for EVP_CipherFinal_ex
out: binary/make-at as red-value! stack/push* 0
outlen: 0
while [inlen > 0] [
chunk: either inlen < max-chunk [inlen] [max-chunk]
handle-error
EVP_CipherUpdate ctx buffer :outlen in-bytes chunk
ctx
binary/rs-append out buffer outlen
inlen: inlen - chunk
in-bytes: in-bytes + chunk
]
handle-error
EVP_CipherFinal_ex ctx buffer :outlen
ctx
binary/rs-append out buffer outlen
free buffer
EVP_CIPHER_CTX_free ctx
stack/set-last as red-value! out
]
]
encrypt-aes256: routine [
in [binary!]
key [binary!]
iv [binary!]
; return [binary!]
] [
crypt-process in key iv EVP_aes_256_cbc yes
]
decrypt-aes256: routine [
ciph [binary!]
key [binary!]
iv [binary!]
; return [binary!]
] [
crypt-process ciph key iv EVP_aes_256_cbc no
]
urandom: routine [
size [integer!]
; return [binary!]
/local
s [series!]
p [byte-ptr!]
out [red-binary!]
] [
out: binary/make-at as red-value! stack/push* size
crypto/urandom binary-bytes out size
s: GET_BUFFER(out)
p: as byte-ptr! s/tail
s/tail: as cell! p + size
stack/set-last as red-value! out
]
encrypt: function [
data [binary!]
pass [string!]
return: [binary!]
] [
salt: urandom 8
hash: pbkdf2/derive pass salt 10000 48 'SHA384
iv: copy at hash 33
key: copy/part hash 32
rejoin [
salt
encrypt-aes256 data key iv
]
]
decrypt: function [
data [binary!]
pass [string!]
return: [binary!]
] [
salt: copy/part data 8
hash: pbkdf2/derive pass salt 10000 48 'SHA384
iv: copy at hash 33
key: copy/part hash 32
decrypt-aes256 at data 9 key iv
]