Added to hex and to base64 and from conversions

This commit is contained in:
Ugljesa Jovanovic 2020-09-26 22:02:51 +02:00
parent 7e2b52a193
commit f113f7805d
No known key found for this signature in database
GPG Key ID: 178E6DFCECCB0E0F
3 changed files with 134 additions and 14 deletions

View File

@ -5,6 +5,11 @@ package com.ionspin.kotlin.crypto.util
* ugljesa.jovanovic@ionspin.com * ugljesa.jovanovic@ionspin.com
* on 31-Aug-2020 * on 31-Aug-2020
*/ */
enum class Base64Variants(val value: Int) {
ORIGINAL(1), ORIGINAL_NO_PADDING(3), URLSAFE(5), URLSAFE_NO_PADDING(7)
}
expect object LibsodiumUtil { expect object LibsodiumUtil {
fun memcmp(first: UByteArray, second: UByteArray) : Boolean fun memcmp(first: UByteArray, second: UByteArray) : Boolean
@ -13,11 +18,11 @@ expect object LibsodiumUtil {
fun pad(unpaddedData : UByteArray, blocksize: Int) : UByteArray fun pad(unpaddedData : UByteArray, blocksize: Int) : UByteArray
fun unpad(paddedData: UByteArray, blocksize: Int) : UByteArray fun unpad(paddedData: UByteArray, blocksize: Int) : UByteArray
fun toBase64(data: UByteArray) : String fun toBase64(data: UByteArray, variant : Base64Variants = Base64Variants.URLSAFE_NO_PADDING) : String
fun toHex(data: UByteArray) : String fun toHex(data: UByteArray) : String
fun toString(data : UByteArray) : String fun toString(data : UByteArray) : String
fun fromBase64(data: String) : UByteArray fun fromBase64(data: String, variant : Base64Variants = Base64Variants.URLSAFE_NO_PADDING) : UByteArray
fun fromHex(data: String) : UByteArray fun fromHex(data: String) : UByteArray
fun fromString(data: String) : UByteArray fun fromString(data: String) : UByteArray
} }

View File

@ -1,6 +1,7 @@
package com.ionspin.kotlin.crypto.util package com.ionspin.kotlin.crypto.util
import com.ionspin.kotlin.bignum.integer.util.hexColumsPrint import com.ionspin.kotlin.bignum.integer.util.hexColumsPrint
import kotlin.math.exp
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -52,4 +53,51 @@ class LibsodiumUtilTest {
input.contentEquals(unpadded) input.contentEquals(unpadded)
} }
} }
@Test
fun testToBase64() {
val input = ubyteArrayOf(1U, 2U, 3U, 4U, 5U, 32U, 64U, 128U, 255U)
val expected = "AQIDBAUgQID_"
val output = LibsodiumUtil.toBase64(input)
println("Output: |$output|")
println("Expected|$expected| ")
assertTrue {
output == expected
}
val reconstructed = LibsodiumUtil.fromBase64(output)
println("Reconstructed: ${reconstructed.toHexString()}")
assertTrue {
reconstructed.contentEquals(input)
}
}
@Test
fun testToBase64Unaligned() {
val input = ubyteArrayOf(1U, 2U, 3U, 4U, 5U, 32U, 64U, 128U, 255U, 128U)
val expected = "AQIDBAUgQID_gA"
val output = LibsodiumUtil.toBase64(input)
println("Output: |$output|")
println("Expected|$expected| ")
assertTrue {
output == expected
}
val reconstructed = LibsodiumUtil.fromBase64(output)
println("Reconstructed: ${reconstructed.toHexString()}")
assertTrue {
reconstructed.contentEquals(input)
}
}
@Test
fun toHex() {
val input = ubyteArrayOf(1U, 2U, 3U, 4U, 5U, 32U, 64U, 128U, 255U, 128U)
val hex = LibsodiumUtil.toHex(input)
assertTrue {
hex == input.toHexString()
}
val reconstructed = LibsodiumUtil.fromHex(hex)
assertTrue {
reconstructed.contentEquals(input)
}
}
} }

View File

@ -1,24 +1,27 @@
package com.ionspin.kotlin.crypto.util package com.ionspin.kotlin.crypto.util
import kotlinx.cinterop.StableRef
import kotlinx.cinterop.addressOf import kotlinx.cinterop.addressOf
import kotlinx.cinterop.convert import kotlinx.cinterop.convert
import kotlinx.cinterop.pin import kotlinx.cinterop.pin
import kotlinx.cinterop.reinterpret import libsodium.sodium_base642bin
import libsodium.sodium_base64_encoded_len
import libsodium.sodium_bin2base64
import libsodium.sodium_bin2hex
import libsodium.sodium_hex2bin
import libsodium.sodium_memcmp import libsodium.sodium_memcmp
import libsodium.sodium_memzero import libsodium.sodium_memzero
import libsodium.sodium_pad import libsodium.sodium_pad
import libsodium.sodium_unpad import libsodium.sodium_unpad
import platform.posix.size_t
/** /**
* Created by Ugljesa Jovanovic * Created by Ugljesa Jovanovic
* ugljesa.jovanovic@ionspin.com * ugljesa.jovanovic@ionspin.com
* on 31-Aug-2020 * on 31-Aug-2020
*/ */
actual object LibsodiumUtil {
actual object LibsodiumUtil {
actual fun memcmp(first: UByteArray, second: UByteArray): Boolean { actual fun memcmp(first: UByteArray, second: UByteArray): Boolean {
val firstPinned = first.pin() val firstPinned = first.pin()
val secondPinned = second.pin() val secondPinned = second.pin()
@ -37,7 +40,7 @@ actual object LibsodiumUtil {
val resultingSize = if (unpaddedData.size % blocksize != 0 ) { val resultingSize = if (unpaddedData.size % blocksize != 0 ) {
((unpaddedData.size / blocksize) + 1 ) * blocksize ((unpaddedData.size / blocksize) + 1 ) * blocksize
} else { } else {
unpaddedData.size unpaddedData.size + 1
} }
val paddedData = UByteArray(resultingSize) val paddedData = UByteArray(resultingSize)
unpaddedData.copyInto(paddedData, 0, 0) unpaddedData.copyInto(paddedData, 0, 0)
@ -57,7 +60,7 @@ actual object LibsodiumUtil {
actual fun unpad(paddedData: UByteArray, blocksize: Int) : UByteArray { actual fun unpad(paddedData: UByteArray, blocksize: Int) : UByteArray {
val paddedDataCopy = paddedData.copyOf() val paddedDataCopy = paddedData.copyOf()
val paddedDataCopyPinned = paddedDataCopy.pin() val paddedDataCopyPinned = paddedDataCopy.pin()
var newSize = ULongArray(1) { 99UL } var newSize = ULongArray(1) { 0UL }
val newSizePinned = newSize.pin() val newSizePinned = newSize.pin()
sodium_unpad( sodium_unpad(
newSizePinned.addressOf(0), newSizePinned.addressOf(0),
@ -75,24 +78,88 @@ actual object LibsodiumUtil {
return unpadded return unpadded
} }
actual fun toBase64(data: UByteArray): String { actual fun toBase64(data: UByteArray, variant : Base64Variants): String {
TODO("not implemented yet") val maxlen = sodium_base64_encoded_len(data.size.convert(), variant.value)
val dataPinned = data.pin()
val result = ByteArray(maxlen.toInt()) { 0 }
val resultPinned = result.pin()
sodium_bin2base64(
resultPinned.addressOf(0),
maxlen,
dataPinned.toPtr(),
data.size.convert(),
variant.value
)
dataPinned.unpin()
resultPinned.unpin()
//Drop '\0'
return result.map { it.toChar() }.dropLast(1).joinToString("")
} }
actual fun toHex(data: UByteArray): String { actual fun toHex(data: UByteArray): String {
TODO("not implemented yet") val hexLen = (data.size * 2) + 1 // +1 for terminator char
val result = ByteArray(hexLen)
val resultPinned = result.pin()
val dataPinned = data.pin()
sodium_bin2hex(
resultPinned.addressOf(0),
hexLen.convert(),
dataPinned.toPtr(),
data.size.convert()
)
resultPinned.unpin()
dataPinned.unpin()
//Drop \0 termination
return result.map { it.toChar() }.dropLast(1).joinToString("")
} }
actual fun toString(data: UByteArray): String { actual fun toString(data: UByteArray): String {
TODO("not implemented yet") TODO("not implemented yet")
} }
actual fun fromBase64(data: String): UByteArray { actual fun fromBase64(data: String, variant : Base64Variants): UByteArray {
TODO("not implemented yet") val maxLength = (data.length * 3) / 4
val intermediaryResult = UByteArray(maxLength) { 0U }
val intermediaryResultPinned = intermediaryResult.pin()
var binLen = ULongArray(1) { 0UL }
var binLenPinned = binLen.pin()
sodium_base642bin(
intermediaryResultPinned.toPtr(),
maxLength.convert(),
data,
data.length.convert(),
null,
binLenPinned.addressOf(0),
null,
variant.value
)
binLenPinned.unpin()
intermediaryResultPinned.unpin()
return if (binLen[0].toInt() != maxLength) {
intermediaryResult.sliceArray(0 until binLen[0].toInt())
} else {
intermediaryResult
}
} }
actual fun fromHex(data: String): UByteArray { actual fun fromHex(data: String): UByteArray {
TODO("not implemented yet") val expectedSize = (data.length + 1) / 2
val result = UByteArray(expectedSize)
val resultPinned = result.pin()
sodium_hex2bin(
resultPinned.toPtr(),
expectedSize.convert(),
data,
data.length.convert(),
null,
null,
null
)
resultPinned.unpin()
return result
} }
actual fun fromString(data: String): UByteArray { actual fun fromString(data: String): UByteArray {