Add high level AEAD tests, implement missing initializations, implement pure decryption
This commit is contained in:
1 parent
579c44fcc7
commit
55b5641f14
10 files changed
+237
-22
No files matched your search
+50
-2
@@ -95,7 +95,6 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val nonce: UByteArray) {
|
||||
}
|
||||
|
||||
fun streamEncrypt(data: UByteArray, additionalData: UByteArray, tag : UByte) : UByteArray {
|
||||
val result = UByteArray(1 + data.size + 16) //Tag marker, ciphertext, mac
|
||||
//get encryption state
|
||||
val block = UByteArray(64) { 0U }
|
||||
ChaCha20Pure.xorWithKeystream(calcKey, calcNonce, block, 0U).copyInto(block) // This is equivalent to the first 64 bytes of keystream
|
||||
@@ -107,6 +106,9 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val nonce: UByteArray) {
|
||||
}
|
||||
block[0] = tag
|
||||
ChaCha20Pure.xorWithKeystream(calcKey, calcNonce, block, 1U).copyInto(block) // This just xors block[0] with keystream
|
||||
println("encrypt block going into poly ----")
|
||||
block.hexColumsPrint()
|
||||
println("encrypt block going into poly end ----")
|
||||
processPolyBytes(poly1305, block) // but updates the mac with the full block!
|
||||
// In libsodium c code, it now sets the first byte to be a tag, we'll just save it for now
|
||||
val encryptedTag = block[0]
|
||||
@@ -121,11 +123,57 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val nonce: UByteArray) {
|
||||
val finalMac = additionalData.size.toULong().toLittleEndianUByteArray() + (ciphertext.size + 64).toULong().toLittleEndianUByteArray()
|
||||
processPolyBytes(poly1305, finalMac)
|
||||
val mac = poly1305.finalizeMac(polyBuffer.sliceArray(0 until polyBufferByteCounter))
|
||||
//TODO process state
|
||||
println("Ciphertext ---------")
|
||||
(ubyteArrayOf(encryptedTag) + ciphertext + mac).hexColumsPrint()
|
||||
println("Ciphertext end ---------")
|
||||
return ubyteArrayOf(encryptedTag) + ciphertext + mac
|
||||
}
|
||||
|
||||
fun streamDecrypt(data: UByteArray, additionalData: UByteArray, tag: UByte) : UByteArray {
|
||||
TODO()
|
||||
val block = UByteArray(64) { 0U }
|
||||
ChaCha20Pure.xorWithKeystream(calcKey, calcNonce, block, 0U).copyInto(block) // This is equivalent to the first 64 bytes of keystream
|
||||
val poly1305 = Poly1305(block)
|
||||
block.overwriteWithZeroes()
|
||||
if (additionalData.isNotEmpty()) {
|
||||
val additionalDataPadded = additionalData + UByteArray(16 - additionalData.size % 16) { 0U }
|
||||
processPolyBytes(poly1305, additionalDataPadded)
|
||||
}
|
||||
block[0] = data[0]
|
||||
ChaCha20Pure.xorWithKeystream(calcKey, calcNonce, block, 1U).copyInto(block)// get the keystream xored with zeroes, but also decrypteg tag marker
|
||||
val tag = block[0] //get the decrypted tag
|
||||
block[0] = data[0] // this brings it back to state that is delivered to poly in encryption function
|
||||
println("Decrypted tag $tag")
|
||||
println("decrypt block going into poly ----")
|
||||
block.hexColumsPrint()
|
||||
println("decrypt block going into poly end ----")
|
||||
processPolyBytes(poly1305, block)
|
||||
// Next we update the poly1305 with ciphertext and padding, BUT the padding in libsodium is not correctly calculated, so it doesn't
|
||||
// pad correctly. https://github.com/jedisct1/libsodium/issues/976
|
||||
// We want to use libsodium in delegated flavour, so we will use the same incorrect padding here.
|
||||
// From security standpoint there are no obvious drawbacks, as padding was initially added to decrease implementation complexity.
|
||||
val ciphertext = data.sliceArray(1 until data.size - 16)
|
||||
processPolyBytes(poly1305, ciphertext + UByteArray(((16U + ciphertext.size.toUInt() - block.size.toUInt()) % 16U).toInt()) { 0U } )
|
||||
val plaintext = ChaCha20Pure.xorWithKeystream(calcKey, calcNonce, ciphertext, 2U)
|
||||
val finalMac = additionalData.size.toULong().toLittleEndianUByteArray() + (ciphertext.size + 64).toULong().toLittleEndianUByteArray()
|
||||
processPolyBytes(poly1305, finalMac)
|
||||
val mac = poly1305.finalizeMac(polyBuffer.sliceArray(0 until polyBufferByteCounter))
|
||||
println("--- mac")
|
||||
mac.hexColumsPrint()
|
||||
println("--- mac end")
|
||||
val expectedMac = data.sliceArray(data.size - 16 until data.size)
|
||||
println("--- expectedMac")
|
||||
expectedMac.hexColumsPrint()
|
||||
println("--- expectedMac end")
|
||||
|
||||
//TODO process state
|
||||
println("Plaintext ---------")
|
||||
plaintext.hexColumsPrint()
|
||||
println("Plaintext end ---------")
|
||||
if (expectedMac.contentEquals(mac).not()){
|
||||
throw InvalidTagException()
|
||||
}
|
||||
return plaintext
|
||||
}
|
||||
|
||||
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package com.ionspin.kotlin.crypto.highlevel
|
||||
|
||||
import com.ionspin.kotlin.crypto.Crypto
|
||||
import com.ionspin.kotlin.crypto.SymmetricKey
|
||||
import com.ionspin.kotlin.crypto.hash.decodeToString
|
||||
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
|
||||
import com.ionspin.kotlin.crypto.util.hexColumsPrint
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* Created by Ugljesa Jovanovic
|
||||
* ugljesa.jovanovic@ionspin.com
|
||||
* on 09-Jul-2020
|
||||
*/
|
||||
class EncryptionTest {
|
||||
@Test
|
||||
fun testMultipartEncryption() {
|
||||
val plaintext = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
|
||||
"Vestibulum maximus tincidunt urna. " +
|
||||
"Nullam sit amet erat id arcu porttitor varius ut at metus. " +
|
||||
"Nunc sit amet felis vel velit ornare gravida. " +
|
||||
"Curabitur tellus lacus, pulvinar a diam at tincidunt.").encodeToUByteArray()
|
||||
plaintext.hexColumsPrint()
|
||||
val additionalData = "Additional data 1".encodeToUByteArray()
|
||||
// val additionalData = ubyteArrayOf()
|
||||
val keyValue = UByteArray(32) { it.toUByte() }
|
||||
val key = SymmetricKey(keyValue)
|
||||
val encryptor = Crypto.Encryption.createMultipartEncryptor(key)
|
||||
val header = encryptor.startEncryption()
|
||||
val ciphertext1 = encryptor.encryptPartialData(plaintext.sliceArray(0 until 100), additionalData)
|
||||
val ciphertext2 = encryptor.encryptPartialData(plaintext.sliceArray(100 until 200))
|
||||
val ciphertext3 = encryptor.encryptPartialData(plaintext.sliceArray(200 until 250))
|
||||
//decrypt
|
||||
val decryptor = Crypto.Encryption.createMultipartDecryptor(key, header)
|
||||
println("Initialized")
|
||||
val plaintext1 = decryptor.decryptPartialData(ciphertext1, additionalData)
|
||||
val plaintext2 = decryptor.decryptPartialData(ciphertext2)
|
||||
val plaintext3 = decryptor.decryptPartialData(ciphertext3)
|
||||
|
||||
val combinedPlaintext = plaintext1.data + plaintext2.data + plaintext3.data
|
||||
println("---- Plaintext -----")
|
||||
plaintext.hexColumsPrint()
|
||||
println("---- Plaintext result -----")
|
||||
combinedPlaintext.hexColumsPrint()
|
||||
assertTrue {
|
||||
plaintext.contentEquals(combinedPlaintext)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user