Further API conversion

This commit is contained in:
Ugljesa Jovanovic authored and Ugljesa Jovanovic committed 2020-06-23 21:39:04 +02:00
1 parent 233ee1bf55
commit 1848de0e8d
24 files changed
+481 -317

No files matched your search

@@ -0,0 +1,164 @@
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.authenticated.*
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bMultipart
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure
import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure
import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure
import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Pure
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
object CryptoInitializerPure : CryptoInitializer {
override suspend fun initialize() {
//Nothing to do atm.
}
fun initializeWithCallback(done: () -> Unit) {
done()
}
override fun isInitialized(): Boolean {
return true
}
}
object CryptoPrimitives : PrimitivesApi {
private fun checkInitialization() {
CryptoInitializerPure.isInitialized()
}
override fun hashBlake2bMultipart(key: UByteArray?, hashLength: Int): Blake2bMultipart {
checkInitialization()
return Blake2bPure(key, hashLength)
}
override fun hashBlake2b(message: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
checkInitialization()
return Blake2bPure.digest(message, key, hashLength)
}
override fun hashSha256Multipart(): com.ionspin.kotlin.crypto.hash.sha.Sha256 {
checkInitialization()
return Sha256Pure()
}
override fun hashSha256(message: UByteArray): UByteArray {
checkInitialization()
return Sha256Pure.digest(inputMessage = message)
}
override fun hashSha512Multipart(): com.ionspin.kotlin.crypto.hash.sha.Sha512 {
checkInitialization()
return Sha512Pure()
}
override fun hashSha512(message: UByteArray): UByteArray {
checkInitialization()
return Sha512Pure.digest(inputMessage = message)
}
override fun deriveKey(
password: String,
salt: String?,
key: String,
associatedData: String,
parallelism: Int,
tagLength: Int,
memory: Int,
numberOfIterations: Int
): ArgonResult {
return Argon2Pure.derive(
password,
salt,
key,
associatedData,
parallelism,
tagLength,
memory,
numberOfIterations
)
}
}
fun SymmetricKey.Companion.randomKey() : SymmetricKey {
return SymmetricKey(SRNG.getRandomBytes(32))
}
object Crypto {
object Hash : HashApi {
override fun hash(data: UByteArray, key : UByteArray) : HashedData {
return HashedData(Blake2bPure.digest(data, key))
}
override fun multipartHash(key: UByteArray?) : com.ionspin.kotlin.crypto.hash.MultipartHash {
return Blake2bPure(key)
}
}
object Encryption : EncryptionApi {
override fun encrypt(key: SymmetricKey, data : Encryptable<*>, additionalData : UByteArray) : EncryptedData {
if (key.value.size != 32) {
throw RuntimeException("Invalid key size! Required 32, supplied ${key.value.size}")
}
val nonce = SRNG.getRandomBytes(24)
return EncryptedData(XChaCha20Poly1305Pure.encrypt(key.value, nonce, data.toEncryptableForm(), additionalData), nonce)
}
override fun <T: Encryptable<T>> decrypt(key: SymmetricKey, encryptedData : EncryptedData, additionalData: UByteArray, byteArrayDeserializer : (UByteArray) -> T) : T {
return byteArrayDeserializer(XChaCha20Poly1305Pure.decrypt(key.value, encryptedData.nonce, encryptedData.ciphertext, additionalData))
}
override fun multipartEncrypt(key: SymmetricKey, additionalData: UByteArray) : MultipartAuthenticatedEncryption {
return MultipartAuthenticatedEncryptor(key, additionalData)
}
override fun multipartDecryptProcessStart(key: SymmetricKey, dataDescriptor: MultipartEncryptedDataDescriptor, additionalData: UByteArray) : MultipartAuthenticatedVerification {
return MultiplatformAuthenticatedVerificator(key, dataDescriptor, additionalData)
}
}
}
class MultipartAuthenticatedEncryptor internal constructor(val key : SymmetricKey, additionalData: UByteArray) : MultipartAuthenticatedEncryption {
val primitive = XChaCha20Poly1305Pure(key.value, additionalData)
override fun encryptPartialData(data: UByteArray): EncryptedDataPart {
return EncryptedDataPart(primitive.encryptPartialData(data))
}
override fun finish(): MultipartEncryptedDataDescriptor {
val finished = primitive.finish()
return MultipartEncryptedDataDescriptor(finished.first, finished.second)
}
}
class MultiplatformAuthenticatedVerificator internal constructor(key: SymmetricKey, multipartEncryptedDataDescriptor: MultipartEncryptedDataDescriptor, additionalData: UByteArray) : MultipartAuthenticatedVerification {
val primitive = XChaCha20Poly1305Pure(key.value, additionalData)
val tag = multipartEncryptedDataDescriptor.data.sliceArray(
multipartEncryptedDataDescriptor.data.size - 16 until multipartEncryptedDataDescriptor.data.size
)
override fun verifyPartialData(data: EncryptedDataPart) {
primitive.verifyPartialData(data.data)
}
override fun finalizeVerificationAndPrepareDecryptor(): MultipartAuthenticatedDecryption {
primitive.checkTag(tag)
return MultipartAuthenticatedDecryptor(primitive)
}
}
class MultipartAuthenticatedDecryptor internal constructor(val encryptor: XChaCha20Poly1305Pure) : MultipartAuthenticatedDecryption {
override fun decryptPartialData(data: EncryptedDataPart): DecryptedDataPart {
return DecryptedDataPart(encryptor.decrypt(data.data))
}
}
@@ -1,185 +0,0 @@
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.authenticated.*
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bPure
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.hash.sha.Sha256Pure
import com.ionspin.kotlin.crypto.hash.sha.Sha512Pure
import com.ionspin.kotlin.crypto.util.toHexString
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 24-May-2020
*/
typealias Blake2bPureStateless = Blake2bPure.Companion
typealias Sha256PureStateless = Sha256Pure.Companion
typealias Sha512PureStateless = Sha512Pure.Companion
object Primitives : CryptoProvider {
override suspend fun initialize() {
//Nothing to do atm.
}
fun initializeWithCallback(done: () -> Unit) {
done()
}
object Blake2b {
fun updateable(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): com.ionspin.kotlin.crypto.hash.blake2b.Blake2b {
checkInitialization()
return Blake2bPure(key, hashLength)
}
fun stateless(message: UByteArray, key: UByteArray = ubyteArrayOf(), hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): UByteArray {
checkInitialization()
return Blake2bPureStateless.digest(message, key, hashLength)
}
}
object Sha256 {
fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha256 {
checkInitialization()
return Sha256Pure()
}
fun stateless(message: UByteArray) : UByteArray{
checkInitialization()
return Sha256PureStateless.digest(inputMessage = message)
}
}
object Sha512 {
fun updateable(): com.ionspin.kotlin.crypto.hash.sha.Sha512 {
checkInitialization()
return Sha512Pure()
}
fun stateless(message: UByteArray) : UByteArray {
checkInitialization()
return Sha512PureStateless.digest(inputMessage = message)
}
}
private fun checkInitialization() {
// Nothing to do atm
}
}
inline class EncryptableString(val content: String) : Encryptable<EncryptableString> {
override fun toEncryptableForm(): UByteArray {
return content.encodeToUByteArray()
}
override fun fromEncryptableForm(): (UByteArray) -> EncryptableString {
return { uByteArray ->
EncryptableString(uByteArray.toByteArray().decodeToString())
}
}
fun asString() : String = content
}
fun String.asEncryptableString() : EncryptableString {
return EncryptableString(this)
}
interface Encryptable<T> {
fun toEncryptableForm() : UByteArray
fun fromEncryptableForm() : (UByteArray) -> T
}
data class HashedData(val hash: UByteArray) {
fun toHexString() : String {
return hash.toHexString()
}
}
data class SymmetricKey(val value : UByteArray) {
companion object {
fun randomKey() : SymmetricKey {
return SymmetricKey(SRNG.getRandomBytes(32))
}
}
}
data class EncryptedData internal constructor(val ciphertext: UByteArray, val nonce: UByteArray) {
}
object PublicApi {
object Hashing {
fun hash(data: UByteArray, key : UByteArray = ubyteArrayOf()) : HashedData {
return HashedData(Blake2bPureStateless.digest(data, key))
}
fun multipartHash(key: UByteArray? = null) : com.ionspin.kotlin.crypto.hash.MultiPartHash {
return Blake2bPure(key)
}
}
object Encryption {
fun authenticatedEncryption(key: SymmetricKey, data : Encryptable<*>, additionalData : UByteArray = ubyteArrayOf()) : EncryptedData {
if (key.value.size != 32) {
throw RuntimeException("Invalid key size! Required 32, supplied ${key.value.size}")
}
val nonce = SRNG.getRandomBytes(24)
return EncryptedData(XChaCha20Poly1305Pure.encrypt(key.value, nonce, data.toEncryptableForm(), additionalData), nonce)
}
fun <T: Encryptable<T>> decrypt(key: SymmetricKey, encryptedData : EncryptedData, additionalData: UByteArray, byteArrayDeserializer : (UByteArray) -> T) : T {
return byteArrayDeserializer(XChaCha20Poly1305Pure.decrypt(key.value, encryptedData.nonce, encryptedData.ciphertext, additionalData))
}
fun multipartAuthenticatedEncrypt(key: SymmetricKey, additionalData: UByteArray) : MultipartAuthenticatedEncryption {
return MultipartAuthenticatedEncryptor(key, additionalData)
}
fun getMultipartVerificator(key: SymmetricKey, dataDescriptor: MultipartEncryptedDataDescriptor, additionalData: UByteArray) : MultipartAuthenticatedVerification {
return MultiplatformAuthenticatedVerificator(key, dataDescriptor, additionalData)
}
}
}
class MultipartAuthenticatedEncryptor internal constructor(val key : SymmetricKey, additionalData: UByteArray) : MultipartAuthenticatedEncryption {
val primitive = XChaCha20Poly1305Pure(key.value, additionalData)
override fun encryptPartialData(data: UByteArray): EncryptedDataPart {
return EncryptedDataPart(primitive.encryptPartialData(data))
}
override fun finish(): MultipartEncryptedDataDescriptor {
val finished = primitive.finish()
return MultipartEncryptedDataDescriptor(finished.first, finished.second)
}
}
class MultiplatformAuthenticatedVerificator internal constructor(key: SymmetricKey, multipartEncryptedDataDescriptor: MultipartEncryptedDataDescriptor, additionalData: UByteArray) : MultipartAuthenticatedVerification {
val primitive = XChaCha20Poly1305Pure(key.value, additionalData)
val tag = multipartEncryptedDataDescriptor.data.sliceArray(
multipartEncryptedDataDescriptor.data.size - 16 until multipartEncryptedDataDescriptor.data.size
)
override fun verifyPartialData(data: EncryptedDataPart) {
primitive.encryptPartialData(data.data)
}
override fun finalizeVerificationAndPrepareDecryptor(): MultipartAuthenticatedDecryption {
primitive.finalizeVerificationAndPrepareDecryptor(tag)
return MultipartAuthenticatedDecryptor(primitive)
}
}
class MultipartAuthenticatedDecryptor internal constructor(val encryptor: XChaCha20Poly1305Pure) : MultipartAuthenticatedDecryption {
override fun decryptPartialData(data: EncryptedDataPart): DecryptedDataPart {
encryptor.decrypt(data.data)
}
}
@@ -1,5 +1,7 @@
package com.ionspin.kotlin.crypto.authenticated
import com.ionspin.kotlin.crypto.InvalidTagException
import com.ionspin.kotlin.crypto.MultipartAuthenticatedDecryption
import com.ionspin.kotlin.crypto.SRNG
import com.ionspin.kotlin.crypto.mac.Poly1305
import com.ionspin.kotlin.crypto.symmetric.ChaCha20Pure
@@ -58,7 +60,7 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val additionalData: UByteArray)
cipherTextWithoutTag.size.toULong().toLittleEndianUByteArray()
val calculatedTag = Poly1305.poly1305Authenticate(authKey, macData)
if (!calculatedTag.contentEquals(tag)) {
RuntimeException("Bad tag!") //TODO replace with specific exception
throw InvalidTagException()
}
//4. Decrypt data
return XChaCha20Pure.xorWithKeystream(key, nonce, cipherTextWithoutTag, 1U)
@@ -106,7 +108,7 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val additionalData: UByteArray)
processPolyBytes(data)
}
fun finalizeVerificationAndPrepareDecryptor(expectedTag: UByteArray): MultipartAuthenticatedDecryption {
fun checkTag(expectedTag: UByteArray) {
val cipherTextPad = UByteArray(16 - processedBytes % 16) { 0U }
val macData = cipherTextPad +
additionalData.size.toULong().toLittleEndianUByteArray() +
@@ -114,7 +116,7 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val additionalData: UByteArray)
processPolyBytes(macData)
val tag = updateableMacPrimitive.finalizeMac()
if (!tag.contentEquals(expectedTag)) {
throw RuntimeException("Invalid tag") //TODO Replace with proper exception
throw InvalidTagException()
}
}
@@ -28,9 +28,9 @@ import com.ionspin.kotlin.crypto.util.rotateRight
*/
class Blake2bPure(val key: UByteArray? = null, val hashLength: Int = 64) : Blake2b {
class Blake2bPure(val key: UByteArray? = null, val hashLength: Int = 64) : Blake2bMultipart {
companion object : Blake2bStateless {
companion object : Blake2b {
//Hack start
//If this line is not included konanc 1.4-M1 fails to link because it cant find ByteArray which is
//a backing class for UByteArray
@@ -29,7 +29,7 @@ class Sha512Pure : Sha512 {
override val MAX_HASH_BYTES: Int = 32
companion object : StatelessSha512 {
companion object : MultipartSha512 {
const val BLOCK_SIZE = 1024
const val BLOCK_SIZE_IN_BYTES = 128
const val CHUNK_SIZE = 80
@@ -385,4 +385,4 @@ class Sha512Pure : Sha512 {
}
}
}
@@ -21,6 +21,7 @@ package com.ionspin.kotlin.crypto.keyderivation.argon2
import com.ionspin.kotlin.bignum.integer.toBigInteger
import com.ionspin.kotlin.crypto.Blake2bPureStateless
import com.ionspin.kotlin.crypto.SRNG
import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.argonBlake2bArbitraryLenghtHash
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
@@ -42,14 +43,7 @@ data class SegmentPosition(
val slice: Int
)
data class ArgonResult(
val hashBytes: UByteArray,
val salt: UByteArray
) {
val hashString by lazy { hashBytes.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") }
val saltString by lazy { salt.map { it.toString(16).padStart(2, '0') }.joinToString(separator = "") }
}