Further API conversion
This commit is contained in:
parent
233ee1bf55
commit
1848de0e8d
@ -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
|
||||||
|
|
||||||
|
}
|
@ -5,8 +5,10 @@ package com.ionspin.kotlin.crypto
|
|||||||
* ugljesa.jovanovic@ionspin.com
|
* ugljesa.jovanovic@ionspin.com
|
||||||
* on 27-May-2020
|
* on 27-May-2020
|
||||||
*/
|
*/
|
||||||
interface CryptoProvider {
|
interface CryptoInitializer {
|
||||||
suspend fun initialize()
|
suspend fun initialize()
|
||||||
|
|
||||||
|
fun isInitialized() : Boolean
|
||||||
|
|
||||||
}
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -27,7 +27,7 @@ interface HashFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface MultiPartHash : HashFunction {
|
interface MultipartHash : HashFunction {
|
||||||
fun update(data : UByteArray)
|
fun update(data : UByteArray)
|
||||||
|
|
||||||
fun digest() : UByteArray
|
fun digest() : UByteArray
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.ionspin.kotlin.crypto.hash.blake2b
|
package com.ionspin.kotlin.crypto.hash.blake2b
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.hash.Hash
|
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
|
* Created by Ugljesa Jovanovic
|
||||||
@ -13,12 +13,12 @@ object Blake2bProperties {
|
|||||||
const val MAX_HASH_BYTES = 64
|
const val MAX_HASH_BYTES = 64
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Blake2b : MultiPartHash {
|
interface Blake2bMultipart : MultipartHash {
|
||||||
override val MAX_HASH_BYTES: Int
|
override val MAX_HASH_BYTES: Int
|
||||||
get() = Blake2bProperties.MAX_HASH_BYTES
|
get() = Blake2bProperties.MAX_HASH_BYTES
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Blake2bStateless : Hash {
|
interface Blake2b : Hash {
|
||||||
override val MAX_HASH_BYTES: Int
|
override val MAX_HASH_BYTES: Int
|
||||||
get() = Blake2bProperties.MAX_HASH_BYTES
|
get() = Blake2bProperties.MAX_HASH_BYTES
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
package com.ionspin.kotlin.crypto.hash.sha
|
package com.ionspin.kotlin.crypto.hash.sha
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.hash.Hash
|
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
|
* Created by Ugljesa Jovanovic
|
||||||
@ -12,7 +12,7 @@ object Sha256Properties {
|
|||||||
const val MAX_HASH_BYTES = 32
|
const val MAX_HASH_BYTES = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Sha256 : MultiPartHash {
|
interface Sha256 : MultipartHash {
|
||||||
override val MAX_HASH_BYTES: Int
|
override val MAX_HASH_BYTES: Int
|
||||||
get() = Sha256Properties.MAX_HASH_BYTES
|
get() = Sha256Properties.MAX_HASH_BYTES
|
||||||
}
|
}
|
||||||
@ -23,4 +23,4 @@ interface StatelessSha256 : Hash {
|
|||||||
fun digest(
|
fun digest(
|
||||||
inputMessage: UByteArray = ubyteArrayOf()
|
inputMessage: UByteArray = ubyteArrayOf()
|
||||||
): UByteArray
|
): UByteArray
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.ionspin.kotlin.crypto.hash.sha
|
package com.ionspin.kotlin.crypto.hash.sha
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.hash.Hash
|
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
|
* Created by Ugljesa Jovanovic
|
||||||
@ -11,15 +11,15 @@ import com.ionspin.kotlin.crypto.hash.MultiPartHash
|
|||||||
object Sha512Properties {
|
object Sha512Properties {
|
||||||
const val MAX_HASH_BYTES = 64
|
const val MAX_HASH_BYTES = 64
|
||||||
}
|
}
|
||||||
interface Sha512 : MultiPartHash {
|
interface Sha512 : MultipartHash {
|
||||||
override val MAX_HASH_BYTES: Int
|
override val MAX_HASH_BYTES: Int
|
||||||
get() = Sha256Properties.MAX_HASH_BYTES
|
get() = Sha256Properties.MAX_HASH_BYTES
|
||||||
}
|
}
|
||||||
interface StatelessSha512 : Hash {
|
interface MultipartSha512 : Hash {
|
||||||
override val MAX_HASH_BYTES: Int
|
override val MAX_HASH_BYTES: Int
|
||||||
get() = Sha512Properties.MAX_HASH_BYTES
|
get() = Sha512Properties.MAX_HASH_BYTES
|
||||||
|
|
||||||
fun digest(
|
fun digest(
|
||||||
inputMessage: UByteArray = ubyteArrayOf()
|
inputMessage: UByteArray = ubyteArrayOf()
|
||||||
): UByteArray
|
): UByteArray
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,13 @@ package com.ionspin.kotlin.crypto.keyderivation
|
|||||||
*/
|
*/
|
||||||
interface KeyDerivationFunction {
|
interface KeyDerivationFunction {
|
||||||
fun derive() : UByteArray
|
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 = "") }
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -3,7 +3,9 @@ package com.ionspin.kotlin.crypto
|
|||||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties
|
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bProperties
|
||||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegated
|
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegated
|
||||||
import com.ionspin.kotlin.crypto.hash.blake2b.Blake2bDelegatedStateless
|
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.hash.sha.*
|
||||||
|
import com.ionspin.kotlin.crypto.keyderivation.ArgonResult
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Ugljesa Jovanovic
|
* Created by Ugljesa Jovanovic
|
||||||
@ -11,18 +13,27 @@ import com.ionspin.kotlin.crypto.hash.sha.*
|
|||||||
* on 24-May-2020
|
* on 24-May-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
object Crypto : CryptoProvider {
|
object CryptoInitializerDelegated : CryptoInitializer {
|
||||||
|
private var initialized = false
|
||||||
override suspend fun initialize() {
|
override suspend fun initialize() {
|
||||||
Initializer.initialize()
|
Initializer.initialize()
|
||||||
|
initialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializeWithCallback(done: () -> Unit) {
|
fun initializeWithCallback(done: () -> Unit) {
|
||||||
|
initialized = true
|
||||||
Initializer.initializeWithCallback(done)
|
Initializer.initializeWithCallback(done)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isInitialized(): Boolean {
|
||||||
|
return initialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CryptoPrimitives : PrimitivesApi {
|
||||||
|
|
||||||
object Blake2b {
|
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()
|
checkInitialization()
|
||||||
return Blake2bDelegated(key, hashLength)
|
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 SymmetricKey.Companion.randomKey() : SymmetricKey {
|
||||||
fun hash(message: String): UByteArray {
|
return SymmetricKey(SRNG.getRandomBytes(32))
|
||||||
return ubyteArrayOf(0U)
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,4 +26,4 @@ package com.ionspin.kotlin.crypto.hash.sha
|
|||||||
|
|
||||||
expect class Sha512Delegated() : Sha512
|
expect class Sha512Delegated() : Sha512
|
||||||
|
|
||||||
expect object Sha512StatelessDelegated : StatelessSha512
|
expect object Sha512StatelessDelegated : MultipartSha512
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.ionspin.kotlin.crypto.hash.blake2b
|
package com.ionspin.kotlin.crypto.hash.blake2b
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.getSodium
|
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.Uint8Array
|
||||||
import org.khronos.webgl.get
|
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
|
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 val MAX_HASH_BYTES: Int = 64
|
||||||
|
|
||||||
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
|
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
|
||||||
@ -59,4 +57,4 @@ actual object Blake2bDelegatedStateless : Blake2bStateless {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.ionspin.kotlin.crypto.hash.sha
|
package com.ionspin.kotlin.crypto.hash.sha
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.getSodium
|
|
||||||
import com.ionspin.kotlin.crypto.getSodium
|
import com.ionspin.kotlin.crypto.getSodium
|
||||||
|
|
||||||
import org.khronos.webgl.Uint8Array
|
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 {
|
override fun digest(inputMessage: UByteArray): UByteArray {
|
||||||
val hashed = getSodium().crypto_hash_sha512(Uint8Array(inputMessage.toByteArray().toTypedArray()))
|
val hashed = getSodium().crypto_hash_sha512(Uint8Array(inputMessage.toByteArray().toTypedArray()))
|
||||||
@ -45,4 +44,4 @@ actual object Sha512StatelessDelegated : StatelessSha512 {
|
|||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
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 {
|
override fun digest(inputMessage: UByteArray, key: UByteArray, hashLength: Int): UByteArray {
|
||||||
@ -37,4 +37,4 @@ actual object Blake2bDelegatedStateless : Blake2bStateless {
|
|||||||
return hashed.toUByteArray()
|
return hashed.toUByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,11 @@ actual class Sha512Delegated : Sha512 {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual object Sha512StatelessDelegated : StatelessSha512 {
|
actual object Sha512StatelessDelegated : MultipartSha512 {
|
||||||
|
|
||||||
override fun digest(inputMessage: UByteArray): UByteArray {
|
override fun digest(inputMessage: UByteArray): UByteArray {
|
||||||
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)
|
val hashed = ByteArray(Sha512Properties.MAX_HASH_BYTES)
|
||||||
Initializer.sodium.crypto_hash_sha512(hashed, inputMessage.toByteArray(), inputMessage.size.toLong())
|
Initializer.sodium.crypto_hash_sha512(hashed, inputMessage.toByteArray(), inputMessage.size.toLong())
|
||||||
return hashed.toUByteArray()
|
return hashed.toUByteArray()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
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.SRNG
|
||||||
import com.ionspin.kotlin.crypto.mac.Poly1305
|
import com.ionspin.kotlin.crypto.mac.Poly1305
|
||||||
import com.ionspin.kotlin.crypto.symmetric.ChaCha20Pure
|
import com.ionspin.kotlin.crypto.symmetric.ChaCha20Pure
|
||||||
@ -58,7 +60,7 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val additionalData: UByteArray)
|
|||||||
cipherTextWithoutTag.size.toULong().toLittleEndianUByteArray()
|
cipherTextWithoutTag.size.toULong().toLittleEndianUByteArray()
|
||||||
val calculatedTag = Poly1305.poly1305Authenticate(authKey, macData)
|
val calculatedTag = Poly1305.poly1305Authenticate(authKey, macData)
|
||||||
if (!calculatedTag.contentEquals(tag)) {
|
if (!calculatedTag.contentEquals(tag)) {
|
||||||
RuntimeException("Bad tag!") //TODO replace with specific exception
|
throw InvalidTagException()
|
||||||
}
|
}
|
||||||
//4. Decrypt data
|
//4. Decrypt data
|
||||||
return XChaCha20Pure.xorWithKeystream(key, nonce, cipherTextWithoutTag, 1U)
|
return XChaCha20Pure.xorWithKeystream(key, nonce, cipherTextWithoutTag, 1U)
|
||||||
@ -106,7 +108,7 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val additionalData: UByteArray)
|
|||||||
processPolyBytes(data)
|
processPolyBytes(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finalizeVerificationAndPrepareDecryptor(expectedTag: UByteArray): MultipartAuthenticatedDecryption {
|
fun checkTag(expectedTag: UByteArray) {
|
||||||
val cipherTextPad = UByteArray(16 - processedBytes % 16) { 0U }
|
val cipherTextPad = UByteArray(16 - processedBytes % 16) { 0U }
|
||||||
val macData = cipherTextPad +
|
val macData = cipherTextPad +
|
||||||
additionalData.size.toULong().toLittleEndianUByteArray() +
|
additionalData.size.toULong().toLittleEndianUByteArray() +
|
||||||
@ -114,7 +116,7 @@ class XChaCha20Poly1305Pure(val key: UByteArray, val additionalData: UByteArray)
|
|||||||
processPolyBytes(macData)
|
processPolyBytes(macData)
|
||||||
val tag = updateableMacPrimitive.finalizeMac()
|
val tag = updateableMacPrimitive.finalizeMac()
|
||||||
if (!tag.contentEquals(expectedTag)) {
|
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
|
//Hack start
|
||||||
//If this line is not included konanc 1.4-M1 fails to link because it cant find ByteArray which is
|
//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
|
//a backing class for UByteArray
|
||||||
|
@ -29,7 +29,7 @@ class Sha512Pure : Sha512 {
|
|||||||
|
|
||||||
override val MAX_HASH_BYTES: Int = 32
|
override val MAX_HASH_BYTES: Int = 32
|
||||||
|
|
||||||
companion object : StatelessSha512 {
|
companion object : MultipartSha512 {
|
||||||
const val BLOCK_SIZE = 1024
|
const val BLOCK_SIZE = 1024
|
||||||
const val BLOCK_SIZE_IN_BYTES = 128
|
const val BLOCK_SIZE_IN_BYTES = 128
|
||||||
const val CHUNK_SIZE = 80
|
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.bignum.integer.toBigInteger
|
||||||
import com.ionspin.kotlin.crypto.Blake2bPureStateless
|
import com.ionspin.kotlin.crypto.Blake2bPureStateless
|
||||||
import com.ionspin.kotlin.crypto.SRNG
|
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.argonBlake2bArbitraryLenghtHash
|
||||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG
|
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.compressionFunctionG
|
||||||
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
|
import com.ionspin.kotlin.crypto.keyderivation.argon2.Argon2Utils.validateArgonParameters
|
||||||
@ -42,14 +43,7 @@ data class SegmentPosition(
|
|||||||
val slice: Int
|
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 = "") }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package com.ionspin.kotlin.crypto.sample
|
package com.ionspin.kotlin.crypto.sample
|
||||||
|
|
||||||
import com.ionspin.kotlin.crypto.Crypto
|
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.hash.encodeToUByteArray
|
||||||
import com.ionspin.kotlin.crypto.util.toHexString
|
import com.ionspin.kotlin.crypto.util.toHexString
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
object Sample {
|
object Sample {
|
||||||
fun runSample() {
|
fun runSample() {
|
||||||
@ -27,4 +23,4 @@ object Sample {
|
|||||||
val statelessResult = Crypto.Blake2b.stateless("test".encodeToByteArray().toUByteArray())
|
val statelessResult = Crypto.Blake2b.stateless("test".encodeToByteArray().toUByteArray())
|
||||||
println("Blake2b stateless: ${statelessResult.toHexString()}")
|
println("Blake2b stateless: ${statelessResult.toHexString()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user