terl / lazysodium-android

An Android implementation of the Libsodium cryptography library. For the lazy dev.
https://github.com/terl/lazysodium-java/wiki
Mozilla Public License 2.0
108 stars 25 forks source link

"Key.fromPlainString" does not works as expected. #41

Closed AlexMesser closed 3 years ago

AlexMesser commented 3 years ago
// generate content encryption key
val cek = lazySodium.keygen(AEAD.Method.XCHACHA20_POLY1305_IETF)
val iv = lazySodium.randomBytesBuf(24)
val data = "Hello world"

// encrypt data
val ciphertext = lazySodium.encrypt(data, null, iv, cek, AEAD.Method.XCHACHA20_POLY1305_IETF)

// "restore" the original key from string
val key = Key.fromPlainString(cek.asPlainString)

// decrypt data using "restored" content encryption key
val decrypted = lazySodium.decrypt(ciphertext, null, iv, key, AEAD.Method.XCHACHA20_POLY1305_IETF)

Result: ����������������������

but if I restore key using HEX - data will be successfully decrypted:

val key = Key.fromHexString(cek.asHexString)
val decrypted = lazySodium.decrypt(ciphertext, null, iv, key, AEAD.Method.XCHACHA20_POLY1305_IETF)

Result: "Hello world"

Also keys restored from hex and from bytes are different from key restored from plain string:

val cek = lazySodium.keygen(AEAD.Method.XCHACHA20_POLY1305_IETF)
val key1 = Key.fromHexString(cek.asHexString).asHexString
val key2 = Key.fromPlainString(cek.asPlainString).asHexString
val key3 = Key.fromBytes(cek.asBytes).asHexString

key1: 80F1C8A6A220D938CB8C72CB14FA740033DFB8A856CDB02F5B55BA23F986FE0C
key2: EFBFBDEFBFBDC8A6EFBFBD20EFBFBD38CB8C72EFBFBD14EFBFBD740033DFB8EFBFBD56CDB02F5B55EFBFBD23EFBFBDEFBFBDEFBFBD0C
key3: 80F1C8A6A220D938CB8C72CB14FA740033DFB8A856CDB02F5B55BA23F986FE0C
AlexMesser commented 3 years ago

Found a solution.

We must initialize LazySodium with ISO_8859_1 charset:

val lazySodium = LazySodiumAndroid(SodiumAndroid(), Charsets.ISO_8859_1)

then we must use the same charset for plain string methods


val cek = lazySodium.keygen(AEAD.Method.XCHACHA20_POLY1305_IETF)

val plainStringCek = cek.getAsPlainString(Charsets.ISO_8859_1)
val restoredCek = Key.fromPlainString(plainStringCek, Charsets.ISO_8859_1)
gurpreet- commented 3 years ago

Using asPlainString and fromPlainString is pretty dangerous because it uses UTF-8 as an encoding. Generally you should encode using Hex (we have these in LS as Key.asHexString and Key.fromHexString) or Base64.

Converting raw bytes to a UTF-8 string can lead to inconsistent outputs as you have found out. In your case you can use:

val cek = lazySodium.keygen(AEAD.Method.XCHACHA20_POLY1305_IETF)

val hexStringCek = cek.asHexString
val restoredCek = Key.fromHexString(hexStringCek)