1
1
using OpenSSL_jll: libcrypto
2
2
3
- using Base: SecretBuffer, SecretBuffer!
3
+ using Base: SecretBuffer, SecretBuffer!, cconvert
4
4
import Base: copy
5
5
6
6
export
@@ -160,17 +160,20 @@ end
160
160
161
161
function get_date_from_utctime (d:: String )
162
162
# Remove fraction seconds if there
163
- d[end ] == ' Z' || error (E_INVALID_DATE)
163
+ d = strip (d)
164
+ endswith (d, ' Z' ) || error (E_INVALID_DATE)
164
165
a = split (d, ' .' )
165
166
length (a) > 1 && (d = a[1 ]* " Z" )
166
167
pfx = length (d) == 15 ? " D:" :
167
168
parse (Int, d[1 : 2 ]) < 50 ? " D:20" : " D:19"
168
169
return CDDate (pfx* d)
169
170
end
170
171
171
- read_cddate (bio:: BIO ) =
172
- bio |> read |> pointer |> unsafe_string |> get_date_from_utctime
173
-
172
+ function read_cddate (bio:: BIO )
173
+ data = read (bio)
174
+ d = transcode (String, data)
175
+ return get_date_from_utctime (d)
176
+ end
174
177
#= ===
175
178
176
179
DigestContext
@@ -236,34 +239,62 @@ end
236
239
CipherContext
237
240
238
241
====#
242
+ abstract type CipherContext end
243
+
244
+ set_padding (_:: CipherContext , _) = nothing
245
+
246
+ Base. reset (_:: CipherContext ) = nothing
247
+
248
+ Base. close (_:: CipherContext ) = UInt8[]
249
+
250
+ init (_:: CipherContext , _:: SecretBuffer , _:: SecretBuffer , _:: Bool ) = nothing
251
+
252
+ update! (_:: CipherContext , indata:: AbstractVector{UInt8} ) = indata
253
+
254
+ function CipherContext (algo:: String , key:: SecretBuffer ,
255
+ iv:: SecretBuffer , isencrypt:: Bool )
256
+ return algo == " RC4" ?
257
+ CipherContextRC4 (key) :
258
+ CipherContextImpl (algo, key, iv, isencrypt)
259
+ end
260
+
261
+ mutable struct CipherContextRC4 <: CipherContext
262
+ key:: SecretBuffer
263
+ end
264
+
265
+ function init (ctx:: CipherContextRC4 , key:: SecretBuffer ,
266
+ _:: SecretBuffer , _:: Bool )
267
+ ctx. key = key
268
+ return nothing
269
+ end
270
+
271
+ function update! (ctx:: CipherContextRC4 , indata:: AbstractVector{UInt8} )
272
+ rc4 ((@view ctx. key. data[1 : ctx. key. size]), indata)
273
+ end
239
274
240
- mutable struct CipherContext
275
+ mutable struct CipherContextImpl <: CipherContext
241
276
data:: Ptr{Cvoid}
242
277
ca:: Ptr{Cvoid}
243
- function CipherContext (algo:: String , key:: SecretBuffer ,
278
+ function CipherContextImpl (algo:: String , key:: SecretBuffer ,
244
279
iv:: SecretBuffer , isencrypt:: Bool )
245
- ca = ccall ((:EVP_get_cipherbyname , libcrypto), Ptr{Cvoid},
246
- (Ptr{Cstring}, ), pointer (algo))
247
- if ca == C_NULL
248
- ca = (algo == " aes_128_cbc" ) ?
249
- ccall ((:EVP_aes_128_cbc , libcrypto), Ptr{Cvoid}, ()) :
250
- (algo == " aes_256_cbc" ) ?
251
- ccall ((:EVP_aes_256_cbc , libcrypto), Ptr{Cvoid}, ()) :
252
- (algo == " aes_256_ecb" ) ?
253
- ccall ((:EVP_aes_256_ecb , libcrypto), Ptr{Cvoid}, ()) :
254
- error (" Unable to find message digest algorithm " * algo)
255
- end
280
+ properties = " provider=default"
281
+ ca = ccall ((:EVP_CIPHER_fetch , libcrypto), Ptr{Cvoid},
282
+ (Ptr{Cvoid}, Ptr{Cstring}, Ptr{Cstring}),
283
+ C_NULL , pointer (algo), pointer (properties))
284
+ ca == C_NULL && error (" Unable to find cipher algorithm " * algo)
256
285
data = ccall ((:EVP_CIPHER_CTX_new , libcrypto), Ptr{Cvoid}, ())
257
286
data == C_NULL && error (" Unable to create cipher context" )
258
287
this = new (data, ca)
259
- finalizer (x-> ccall ((:EVP_CIPHER_CTX_free , libcrypto), Cvoid,
260
- (Ptr{Cvoid}, ), x. data), this)
288
+ finalizer (this) do x
289
+ ccall ((:EVP_CIPHER_CTX_free , libcrypto), Cvoid, (Ptr{Cvoid}, ), x. data)
290
+ ccall ((:EVP_CIPHER_free , libcrypto), Cvoid, (Ptr{Cvoid}, ), x. ca)
291
+ end
261
292
init (this, key, iv, isencrypt)
262
293
return this
263
294
end
264
295
end
265
296
266
- function init (ctx:: CipherContext , key:: SecretBuffer ,
297
+ function init (ctx:: CipherContextImpl , key:: SecretBuffer ,
267
298
iv:: SecretBuffer , isencrypt:: Bool )
268
299
enc = Cint (isencrypt ? 1 : 0 )
269
300
piv = iv. size > 0 ? pointer (iv. data) : C_NULL
@@ -278,21 +309,21 @@ function init(ctx::CipherContext, key::SecretBuffer,
278
309
return nothing
279
310
end
280
311
281
- function set_padding (ctx:: CipherContext , pad_size:: Int )
312
+ function set_padding (ctx:: CipherContextImpl , pad_size:: Int )
282
313
ret = ccall ((:EVP_CIPHER_CTX_set_padding , libcrypto), Cint,
283
314
(Ptr{Cvoid}, Cint), ctx. data, Cint (pad_size))
284
315
openssl_error (ret)
285
316
end
286
317
287
- function Base. reset (ctx:: CipherContext )
318
+ function Base. reset (ctx:: CipherContextImpl )
288
319
ret = ccall ((:EVP_CIPHER_CTX_reset , libcrypto), Cint,
289
320
(Ptr{Cvoid}, ), ctx. data)
290
321
openssl_error (ret)
291
322
end
292
323
293
324
const EVP_MAX_BLOCK_LENGTH = Cint (32 )
294
325
295
- function update! (ctx:: CipherContext , indata:: AbstractVector{UInt8} )
326
+ function update! (ctx:: CipherContextImpl , indata:: AbstractVector{UInt8} )
296
327
inlen = Cint (length (indata))
297
328
out, outlen = Vector {UInt8} (undef, inlen + EVP_MAX_BLOCK_LENGTH),
298
329
Ref (inlen + EVP_MAX_BLOCK_LENGTH)
@@ -303,11 +334,10 @@ function update!(ctx::CipherContext, indata::AbstractVector{UInt8})
303
334
return resize! (out, outlen[])
304
335
end
305
336
306
- update! (ctx:: CipherContext , s:: SecretBuffer ) =
337
+ update! (ctx:: CipherContextImpl , s:: SecretBuffer ) =
307
338
update! (ctx, (@view s. data[1 : s. size]))
308
339
309
-
310
- function Base. close (ctx:: CipherContext )
340
+ function Base. close (ctx:: CipherContextImpl )
311
341
c_value = Vector {UInt8} (undef, EVP_MAX_BLOCK_LENGTH)
312
342
c_len = Ref (EVP_MAX_BLOCK_LENGTH)
313
343
ret = ccall ((:EVP_CipherFinal_ex , libcrypto), Cint,
@@ -342,7 +372,7 @@ mutable struct CertStore
342
372
343
373
ret = ccall ((:X509_STORE_load_locations , libcrypto), Cint,
344
374
(Ptr{Cvoid}, Ptr{Cstring}, Ptr{Cstring}),
345
- store, transcode (UInt8, cacerts), C_NULL )
375
+ store, pointer ( cacerts), C_NULL )
346
376
openssl_error (ret)
347
377
348
378
ccall ((:X509_STORE_set_default_paths , libcrypto),
@@ -879,7 +909,7 @@ function read_pkcs12(fn::AbstractString, pw::SecretBuffer)
879
909
ret = ccall ((:PKCS12_parse , libcrypto), Cint,
880
910
(Ptr{Cvoid}, Ptr{Cstring},
881
911
Ptr{Ptr{Cvoid}}, Ptr{Ptr{Cvoid}}, Ptr{Ptr{Cvoid}}),
882
- p12, pointer (pw . data ), xkey, xcert, xca)
912
+ p12, cconvert (Cstring, pw ), xkey, xcert, xca)
883
913
openssl_error (ret)
884
914
return Cert (xcert[]), PKey (xkey[])
885
915
end
@@ -927,3 +957,38 @@ function decrypt(ci::CMSContentInfo, key::PKey, cert::Cert,
927
957
return nothing
928
958
end
929
959
end
960
+
961
+ # Adapted from https://gist.github.com/rverton/a44fc8ca67ab9ec32089 for 1-indexing
962
+
963
+ const N = 256
964
+
965
+ function ksa (K:: AbstractVector{UInt8} )
966
+ lk = length (K)
967
+ S = [UInt8 (i) for i= 0 : (N- 1 )]
968
+ j = 0
969
+ lk == 0 && return S
970
+ for i = 0 : (N- 1 )
971
+ ik = i % lk
972
+ j = (j + S[i+ 1 ] + K[ik+ 1 ]) % N
973
+ S[i+ 1 ], S[j+ 1 ] = S[j+ 1 ], S[i+ 1 ]
974
+ end
975
+ return S
976
+ end
977
+
978
+ function prga (S, plaintext:: AbstractVector{UInt8} )
979
+ i = j = 0
980
+ len = length (plaintext)
981
+ ciphertext = copy (plaintext)
982
+ for n = 0 : (len- 1 )
983
+ i = (i + 1 ) % N
984
+ j = (j + S[i+ 1 ]) % N
985
+
986
+ S[i+ 1 ], S[j+ 1 ] = S[j+ 1 ], S[i+ 1 ]
987
+ t = (S[i+ 1 ] + S[j+ 1 ]) % N
988
+
989
+ ciphertext[n+ 1 ] = xor (S[t+ 1 ], plaintext[n+ 1 ])
990
+ end
991
+ return ciphertext
992
+ end
993
+
994
+ rc4 (key:: AbstractVector{UInt8} , plaintext:: AbstractVector{UInt8} ) = prga (ksa (key), plaintext)
0 commit comments