All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cryptostring.Cryptostringer.kt Maven / Gradle / Ivy

There is a newer version: 0.3.1
Show newest version
package se.wollan.crypto.cryptostring

import se.wollan.crypto.SymmetricEncryptor
import se.wollan.crypto.fromBase64
import se.wollan.crypto.keyvault.KeyVault
import se.wollan.crypto.toBase64

// It's a crypto-string if it starts with this character
private const val CRYPTO_BOM: Char = '\u2060' // https://en.wikipedia.org/wiki/Word_joiner - \u200B could also be used

// The rest of the crypto-string is always base64 of a byte array where the first byte defines the encoding of the rest
private const val ENC_AES_GCM: Byte = 0x01

interface Cryptostringer {

    // noop if already cryptostring
    // KeyVaultIsLockedException
    suspend fun encode(plaintext: String): String

    // noop if already plaintext
    // KeyVaultIsLockedException
    suspend fun decode(cryptostring: String): String
}

internal class CryptostringerImpl(
    private val encryptor: SymmetricEncryptor,
    private val keyVault: KeyVault
) : Cryptostringer {

    override suspend fun encode(plaintext: String): String {
        if (plaintext.startsWith(CRYPTO_BOM))
            return plaintext

        val secretKey = keyVault.getSecretKey()
        val ciphermessage = encryptor.encrypt(plaintext.toByteArray(Charsets.UTF_8), secretKey)

        val fullMessage = ByteArray(ciphermessage.size + 1)
        fullMessage[0] = ENC_AES_GCM
        ciphermessage.copyInto(fullMessage, 1, 0, ciphermessage.size)

        return CRYPTO_BOM + fullMessage.toBase64()
    }

    override suspend fun decode(cryptostring: String): String {
        if (!cryptostring.startsWith(CRYPTO_BOM))
            return cryptostring

        val fullMessage = cryptostring.substring(1).fromBase64()
        check(fullMessage.isNotEmpty() && fullMessage[0] == ENC_AES_GCM) { "not a valid crypto-string encoding!" }

        val ciphermessage = ByteArray(fullMessage.size - 1)
        fullMessage.copyInto(ciphermessage, 0, 1, fullMessage.size)

        val secretKey = keyVault.getSecretKey()
        val plainbytes = encryptor.decrypt(ciphermessage, secretKey)

        val plaintext = plainbytes.toString(Charsets.UTF_8)
        return plaintext
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy