Further API conversion

This commit is contained in:
Ugljesa Jovanovic 2020-06-23 21:39:04 +02:00 committed by Ugljesa Jovanovic
parent 233ee1bf55
commit 1848de0e8d
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
24 changed files with 481 additions and 317 deletions

View File

@ -0,0 +1,92 @@
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.hash.MultipartHash
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toHexString
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 23-Jun-2020
*/
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 {
}
}
data class EncryptedData constructor(val ciphertext: UByteArray, val nonce: UByteArray) {
}
interface HashApi {
fun hash(data: UByteArray, key : UByteArray = ubyteArrayOf()) : HashedData
fun multipartHash(key: UByteArray? = null) : MultipartHash
}
interface EncryptionApi {
fun encrypt(key: SymmetricKey, data : Encryptable<*>, additionalData : UByteArray = ubyteArrayOf()) : EncryptedData
fun <T: Encryptable<T>> decrypt(key: SymmetricKey, encryptedData : EncryptedData, additionalData: UByteArray, byteArrayDeserializer : (UByteArray) -> T) : T
fun multipartEncrypt(key: SymmetricKey, additionalData: UByteArray) : MultipartAuthenticatedEncryption
fun multipartDecryptProcessStart(key: SymmetricKey, dataDescriptor: MultipartEncryptedDataDescriptor, additionalData: UByteArray) : MultipartAuthenticatedVerification
}
interface AuthenticatedEncryption {
fun encrypt(key: UByteArray, nonce: UByteArray, message: UByteArray, additionalData: UByteArray) : UByteArray
fun decrypt(key: UByteArray, nonce: UByteArray, cipherText: UByteArray, additionalData: UByteArray) : UByteArray
}
data class EncryptedDataPart(val data : UByteArray)
data class DecryptedDataPart(val data : UByteArray)
data class MultipartEncryptedDataDescriptor(val data: UByteArray, val nonce: UByteArray)
class InvalidTagException : RuntimeException("Tag mismatch! Encrypted data is corrupted or tampered with.")
interface MultipartAuthenticatedVerification {
fun verifyPartialData(data: EncryptedDataPart)
fun finalizeVerificationAndPrepareDecryptor() : MultipartAuthenticatedDecryption
}
interface MultipartAuthenticatedDecryption {
fun decryptPartialData(data: EncryptedDataPart) : DecryptedDataPart
}
interface MultipartAuthenticatedEncryption {
fun encryptPartialData(data: UByteArray) : EncryptedDataPart
fun finish() : MultipartEncryptedDataDescriptor
}

View File

@ -5,8 +5,10 @@ package com.ionspin.kotlin.crypto
* ugljesa.jovanovic@ionspin.com
* on 27-May-2020
*/
interface CryptoProvider {
interface CryptoInitializer {
suspend fun initialize()
fun isInitialized() : Boolean
}

View File

@ -0,0 +1,37 @@
package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bMultipart
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties
import com.ionspin.kotlin.crypto.hash.sha.Sha256
import com.ionspin.kotlin.crypto.hash.sha.Sha512
import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 23-Jun-2020
*/
interface PrimitivesApi {
fun hashBlake2bMultipart(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): Blake2bMultipart
fun hashBlake2b(message: UByteArray, key: UByteArray = ubyteArrayOf(), hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): UByteArray
fun hashSha256Multipart(): Sha256
fun hashSha256(message: UByteArray) : UByteArray
fun hashSha512Multipart(): Sha512
fun hashSha512(message: UByteArray) : UByteArray
fun deriveKey(
password: String,
salt: String? = null,
key: String,
associatedData: String,
parallelism: Int = 16,
tagLength: Int = 64,
memory: Int = 4096,
numberOfIterations: Int = 10,
) : ArgonResult
}

View File

@ -1,42 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 14-Jun-2020
*/
interface Aes256GcmStateless {
fun encrypt(message: UByteArray, additionalData: UByteArray, rawData : UByteArray, key: Aes256GcmKey) : Aes256GcmEncryptionResult
fun decrypt(encryptedData: UByteArray, nonce: UByteArray, key : Aes256GcmKey) : UByteArray
}
data class Aes256GcmEncryptionResult(val cyphertext : UByteArray, val additionalData: UByteArray, val nonce: UByteArray, val tag: UByteArray) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Aes256GcmEncryptionResult
if (cyphertext != other.cyphertext) return false
if (additionalData != other.additionalData) return false
if (nonce != other.nonce) return false
if (tag != other.tag) return false
return true
}
override fun hashCode(): Int {
var result = cyphertext.hashCode()
result = 31 * result + additionalData.hashCode()
result = 31 * result + nonce.hashCode()
result = 31 * result + tag.hashCode()
return result
}
}
interface Aes256GcmKey {
val key : UByteArray
}

View File

@ -1,36 +0,0 @@
package com.ionspin.kotlin.crypto.authenticated
/**
* Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com
* on 22-Jun-2020
*/
interface AuthenticatedEncryption {
fun encrypt(key: UByteArray, nonce: UByteArray, message: UByteArray, additionalData: UByteArray) : UByteArray
fun decrypt(key: UByteArray, nonce: UByteArray, cipherText: UByteArray, additionalData: UByteArray) : UByteArray
}
data class EncryptedDataPart(val data : UByteArray)
data class DecryptedDataPart(val data : UByteArray)
data class MultipartEncryptedDataDescriptor(val data: UByteArray, val nonce: UByteArray)
interface MultipartAuthenticatedVerification {
fun verifyPartialData(data: EncryptedDataPart)
fun finalizeVerificationAndPrepareDecryptor() : MultipartAuthenticatedDecryption
}
interface MultipartAuthenticatedDecryption {
fun decryptPartialData(data: EncryptedDataPart) : DecryptedDataPart
}
interface MultipartAuthenticatedEncryption {
fun encryptPartialData(data: UByteArray) : EncryptedDataPart
fun finish() : MultipartEncryptedDataDescriptor
}

View File

@ -27,7 +27,7 @@ interface HashFunction {
}
interface MultiPartHash : HashFunction {
interface MultipartHash : HashFunction {
fun update(data : UByteArray)
fun digest() : UByteArray

View File

@ -1,7 +1,7 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.hash.Hash
import com.ionspin.kotlin.crypto.hash.MultiPartHash
import com.ionspin.kotlin.crypto.hash.MultipartHash
/**
* Created by Ugljesa Jovanovic
@ -13,12 +13,12 @@ object Blake2bProperties {
const val MAX_HASH_BYTES = 64
}
interface Blake2b : MultiPartHash {
interface Blake2bMultipart : MultipartHash {
override val MAX_HASH_BYTES: Int
get() = Blake2bProperties.MAX_HASH_BYTES
}
interface Blake2bStateless : Hash {
interface Blake2b : Hash {
override val MAX_HASH_BYTES: Int
get() = Blake2bProperties.MAX_HASH_BYTES

View File

@ -1,7 +1,7 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.hash.Hash
import com.ionspin.kotlin.crypto.hash.MultiPartHash
import com.ionspin.kotlin.crypto.hash.MultipartHash
/**
* Created by Ugljesa Jovanovic
@ -12,7 +12,7 @@ object Sha256Properties {
const val MAX_HASH_BYTES = 32
}
interface Sha256 : MultiPartHash {
interface Sha256 : MultipartHash {
override val MAX_HASH_BYTES: Int
get() = Sha256Properties.MAX_HASH_BYTES
}

View File

@ -1,7 +1,7 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.hash.Hash
import com.ionspin.kotlin.crypto.hash.MultiPartHash
import com.ionspin.kotlin.crypto.hash.MultipartHash
/**
* Created by Ugljesa Jovanovic
@ -11,11 +11,11 @@ import com.ionspin.kotlin.crypto.hash.MultiPartHash
object Sha512Properties {
const val MAX_HASH_BYTES = 64
}
interface Sha512 : MultiPartHash {
interface Sha512 : MultipartHash {
override val MAX_HASH_BYTES: Int
get() = Sha256Properties.MAX_HASH_BYTES
}
interface StatelessSha512 : Hash {
interface MultipartSha512 : Hash {
override val MAX_HASH_BYTES: Int
get() = Sha512Properties.MAX_HASH_BYTES

View File

@ -24,3 +24,12 @@ package com.ionspin.kotlin.crypto.keyderivation
interface KeyDerivationFunction {
fun derive() : UByteArray
}
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 = "") }
}

View File

@ -3,7 +3,9 @@ package com.ionspin.kotlin.crypto
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegated
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegatedStateless
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bMultipart
import com.ionspin.kotlin.crypto.hash.sha.*
import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
/**
* Created by Ugljesa Jovanovic
@ -11,18 +13,27 @@ import com.ionspin.kotlin.crypto.hash.sha.*
* on 24-May-2020
*/
object Crypto : CryptoProvider {
object CryptoInitializerDelegated : CryptoInitializer {
private var initialized = false
override suspend fun initialize() {
Initializer.initialize()
initialized = true
}
fun initializeWithCallback(done: () -> Unit) {
initialized = true
Initializer.initializeWithCallback(done)
}
override fun isInitialized(): Boolean {
return initialized
}
}
object CryptoPrimitives : PrimitivesApi {
object Blake2b {
fun updateable(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): com.ionspin.kotlin.crypto.hash.blake2b.Blake2b {
fun updateable(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES): com.ionspin.kotlin.crypto.hash.blake2b.Blake2bMultipart {
checkInitialization()
return Blake2bDelegated(key, hashLength)
}
@ -63,12 +74,135 @@ object Crypto : CryptoProvider {
}
}
override fun hashBlake2bMultipart(key: UByteArray?, hashLength: Int): Blake2bMultipart {
checkInitialization()
return Blake2bDelegated(key, hashLength)
}
override fun hashBlake2b(message: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
checkInitialization()
return Blake2bDelegatedStateless.digest(message, key, hashLength)
}
override fun hashSha256Multipart(): com.ionspin.kotlin.crypto.hash.sha.Sha256 {
checkInitialization()
return Sha256Delegated()
}
override fun hashSha256(message: UByteArray): UByteArray {
checkInitialization()
return Sha256StatelessDelegated.digest(inputMessage = message)
}
override fun hashSha512Multipart(): com.ionspin.kotlin.crypto.hash.sha.Sha512 {
checkInitialization()
return Sha512Delegated()
}
override fun hashSha512(message: UByteArray): UByteArray {
checkInitialization()
return Sha512StatelessDelegated.digest(inputMessage = message)
}
override fun deriveKey(
password: String,
salt: String?,
key: String,
associatedData: String,
parallelism: Int,
tagLength: Int,
memory: Int,
numberOfIterations: Int
): ArgonResult {
// return Argon2Delegated.derive(
// password,
// salt,
// key,
// associatedData,
// parallelism,
// tagLength,
// memory,
// numberOfIterations
// )
TODO()
}
}
object SimpleCrypto {
fun hash(message: String): UByteArray {
return ubyteArrayOf(0U)
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(Blake2bDelegatedStateless.digest(data, key))
}
override fun multipartHash(key: UByteArray?) : com.ionspin.kotlin.crypto.hash.MultipartHash {
return Blake2bDelegated(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))
}
}

View File

@ -23,9 +23,9 @@ package com.ionspin.kotlin.crypto.hash.blake2b
*/
expect class Blake2bDelegated(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES) : Blake2b
expect class Blake2bDelegated(key: UByteArray? = null, hashLength: Int = Blake2bProperties.MAX_HASH_BYTES) : Blake2bMultipart
expect object Blake2bDelegatedStateless : Blake2bStateless
expect object Blake2bDelegatedStateless : Blake2b

View File

@ -26,4 +26,4 @@ package com.ionspin.kotlin.crypto.hash.sha
expect class Sha512Delegated() : Sha512
expect object Sha512StatelessDelegated : StatelessSha512
expect object Sha512StatelessDelegated : MultipartSha512

View File

@ -1,8 +1,6 @@
package com.ionspin.kotlin.crypto.hash.blake2b
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.hash.sha.Sha256StatelessDelegated
import com.ionspin.kotlin.crypto.util.toHexString
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
@ -13,7 +11,7 @@ import org.khronos.webgl.get
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2b {
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2bMultipart {
override val MAX_HASH_BYTES: Int = 64
@ -43,7 +41,7 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLengt
actual object Blake2bDelegatedStateless : Blake2bStateless {
actual object Blake2bDelegatedStateless : Blake2b {
override val MAX_HASH_BYTES: Int = 64
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {

View File

@ -1,6 +1,5 @@
package com.ionspin.kotlin.crypto.hash.sha
import com.ionspin.kotlin.crypto.getSodium
import com.ionspin.kotlin.crypto.getSodium
import org.khronos.webgl.Uint8Array
@ -35,7 +34,7 @@ actual class Sha512Delegated : Sha512 {
}
actual object Sha512StatelessDelegated : StatelessSha512 {
actual object Sha512StatelessDelegated : MultipartSha512 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = getSodium().crypto_hash_sha512(Uint8Array(inputMessage.toByteArray().toTypedArray()))

View File

@ -8,7 +8,7 @@ import com.ionspin.kotlin.crypto.Initializer.sodium
*/
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2b {
actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLength: Int) : Blake2bMultipart {
val state = ByteArray(sodium.crypto_generichash_statebytes())
@ -28,7 +28,7 @@ actual class Blake2bDelegated actual constructor(key: UByteArray?, val hashLengt
}
actual object Blake2bDelegatedStateless : Blake2bStateless {
actual object Blake2bDelegatedStateless : Blake2b {
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {

View File

@ -30,7 +30,7 @@ actual class Sha512Delegated : Sha512 {
}
actual object Sha512StatelessDelegated : StatelessSha512 {
actual object Sha512StatelessDelegated : MultipartSha512 {
override fun digest(inputMessage: UByteArray): UByteArray {
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)

View File

@ -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))
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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

View File

@ -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 = "") }
}

View File

@ -1,12 +1,8 @@
package com.ionspin.kotlin.crypto.sample
import com.ionspin.kotlin.crypto.Crypto
import com.ionspin.kotlin.crypto.CryptoProvider
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2b
import com.ionspin.kotlin.crypto.hash.encodeToUByteArray
import com.ionspin.kotlin.crypto.util.toHexString
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
object Sample {
fun runSample() {