@@ -8,8 +8,6 @@ import dev.whyoleg.cryptography.*
88import dev.whyoleg.cryptography.algorithms.*
99import dev.whyoleg.cryptography.providers.openssl3.internal.*
1010import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
11- import dev.whyoleg.cryptography.random.*
12- import kotlinx.cinterop.*
1311import kotlin.experimental.*
1412import kotlin.native.ref.*
1513
@@ -24,138 +22,15 @@ internal object Openssl3AesCbc : AES.CBC, Openssl3Aes<AES.CBC.Key>() {
2422 else -> error(" Unsupported key size" )
2523 }
2624
27- override fun cipher (padding : Boolean ): AES .IvCipher = AesCbcCipher (algorithm, key, padding)
28- }
29- }
30-
31- private const val ivSizeBytes = 16 // bytes for CBC
32-
33- private class AesCbcCipher (
34- algorithm : String ,
35- private val key : ByteArray ,
36- private val padding : Boolean ,
37- ) : AES.IvCipher {
38-
39- private val cipher = EVP_CIPHER_fetch (null , algorithm, null )
40-
41- @OptIn(ExperimentalNativeApi ::class )
42- private val cleaner = createCleaner(cipher, ::EVP_CIPHER_free )
43-
44- override fun encryptBlocking (plaintext : ByteArray ): ByteArray {
45- val iv = CryptographyRandom .nextBytes(ivSizeBytes)
46- return iv + encryptWithIvBlocking(iv, plaintext)
47- }
48-
49- override fun encryptWithIvBlocking (iv : ByteArray , plaintext : ByteArray ): ByteArray = memScoped {
50- require(iv.size == ivSizeBytes) { " IV size is wrong" }
51-
52- val context = EVP_CIPHER_CTX_new ()
53- try {
54- checkError(
55- EVP_EncryptInit_ex2 (
56- ctx = context,
57- cipher = cipher,
58- key = key.refToU(0 ),
59- iv = iv.refToU(0 ),
60- params = null
61- )
62- )
63- checkError(EVP_CIPHER_CTX_set_padding (context, if (padding) 1 else 0 ))
64-
65- val blockSize = checkError(EVP_CIPHER_CTX_get_block_size (context))
66- val ciphertextOutput = ByteArray (blockSize + plaintext.size)
67-
68- val outl = alloc<IntVar >()
69-
70- checkError(
71- EVP_EncryptUpdate (
72- ctx = context,
73- out = ciphertextOutput.refToU(0 ),
74- outl = outl.ptr,
75- `in ` = plaintext.safeRefToU(0 ),
76- inl = plaintext.size
77- )
78- )
79-
80- val producedByUpdate = outl.value
81-
82- checkError(
83- EVP_EncryptFinal_ex (
84- ctx = context,
85- out = ciphertextOutput.refToU(outl.value),
86- outl = outl.ptr
87- )
88- )
89-
90- val produced = producedByUpdate + outl.value
91- ciphertextOutput.ensureSizeExactly(produced)
92- } finally {
93- EVP_CIPHER_CTX_free (context)
94- }
95- }
96-
97- override fun decryptBlocking (ciphertext : ByteArray ): ByteArray {
98- require(ciphertext.size >= ivSizeBytes) { " Ciphertext is too short" }
99-
100- return decrypt(
101- iv = ciphertext,
102- ciphertext = ciphertext,
103- ciphertextStartIndex = ivSizeBytes,
104- )
105- }
106-
107- override fun decryptWithIvBlocking (iv : ByteArray , ciphertext : ByteArray ): ByteArray {
108- require(iv.size == ivSizeBytes) { " IV size is wrong" }
109-
110- return decrypt(
111- iv = iv,
112- ciphertext = ciphertext,
113- ciphertextStartIndex = 0 ,
114- )
115- }
116-
117- private fun decrypt (iv : ByteArray , ciphertext : ByteArray , ciphertextStartIndex : Int ): ByteArray = memScoped {
118- val context = EVP_CIPHER_CTX_new ()
119- try {
120- checkError(
121- EVP_DecryptInit_ex2 (
122- ctx = context,
123- cipher = cipher,
124- key = key.refToU(0 ),
125- iv = iv.refToU(0 ),
126- params = null
127- )
128- )
129- checkError(EVP_CIPHER_CTX_set_padding (context, if (padding) 1 else 0 ))
130-
131- val blockSize = checkError(EVP_CIPHER_CTX_get_block_size (context))
132- val plaintextOutput = ByteArray (blockSize + ciphertext.size - ciphertextStartIndex)
133-
134- val outl = alloc<IntVar >()
135-
136- checkError(
137- EVP_DecryptUpdate (
138- ctx = context,
139- out = plaintextOutput.refToU(0 ),
140- outl = outl.ptr,
141- `in ` = ciphertext.safeRefToU(ciphertextStartIndex),
142- inl = ciphertext.size - ciphertextStartIndex
143- )
144- )
25+ private val cipher = EVP_CIPHER_fetch (null , algorithm, null )
14526
146- val producedByUpdate = outl.value
27+ @OptIn(ExperimentalNativeApi ::class )
28+ private val cleaner = createCleaner(cipher, ::EVP_CIPHER_free )
14729
148- checkError(
149- EVP_DecryptFinal_ex (
150- ctx = context,
151- outm = plaintextOutput.refToU(producedByUpdate),
152- outl = outl.ptr
153- )
154- )
155- val produced = producedByUpdate + outl.value
156- plaintextOutput.ensureSizeExactly(produced)
157- } finally {
158- EVP_CIPHER_CTX_free (context)
30+ override fun cipher (padding : Boolean ): AES .IvCipher {
31+ return Openssl3AesIvCipher (cipher, key, ivSize = 16 ) { context ->
32+ checkError(EVP_CIPHER_CTX_set_padding (context, if (padding) 1 else 0 ))
33+ }
15934 }
16035 }
16136}
0 commit comments