libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 45d11337f6ae92c592eb4ad96422a5fa9b2a76f2
parent af131544dc7947a519d0def1502fed6bf74e1d0d
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Sat, 28 Mar 2020 10:43:19 +0100

Crockford's base32 decoder, EdDSA public key import.

Diffstat:
Mutil/build.gradle | 3++-
Mutil/src/main/kotlin/strings.kt | 24+++++++++++++++++++++++-
Mutil/src/test/kotlin/CryptoUtilTest.kt | 29++++++++++++++++++++++++-----
3 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/util/build.gradle b/util/build.gradle @@ -38,9 +38,10 @@ dependencies { implementation "javax.activation:activation:1.1" implementation "org.glassfish.jaxb:jaxb-runtime:2.3.1" implementation 'org.apache.santuario:xmlsec:2.1.4' - implementation group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.45' + implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.64' implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.28.0' implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.20' + implementation("com.msiops.ground:ground-crockford32:0.1") testImplementation group: 'junit', name: 'junit', version: '4.12' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.3.50' diff --git a/util/src/main/kotlin/strings.kt b/util/src/main/kotlin/strings.kt @@ -1,6 +1,8 @@ package tech.libeufin.util +import org.apache.commons.codec.binary.Base32 import java.math.BigInteger import java.util.* +import com.msiops.ground.crockford32.Crockford32 fun ByteArray.toHexString() : String { @@ -41,9 +43,29 @@ fun base64ToBytes(encoding: String): ByteArray { return Base64.getDecoder().decode(encoding) } +/** + * Crockford's base32 decoding. + */ +fun base32ToBytes(encoding: String): ByteArray { + val i: BigInteger = Crockford32.decode(encoding) + if ((i.bitLength() % 4) != 0) { + logger.debug("No extra 4-bits element added (bitLength: ${i.bitLength()})") + return i.toByteArray() + } + val extraByteBlob = i.toByteArray() + return Arrays.copyOfRange(extraByteBlob, 1, extraByteBlob.size) +} + +/** + * Crockford's base32 encoding. + */ +fun bytesToBase32(bytes: ByteArray): String { + return Crockford32.encode(BigInteger(bytes)) +} + fun BigInteger.toUnsignedHexString(): String { val signedValue = this.toByteArray() - require(this.signum() > 0) { "number must be positive"} + require(this.signum() > 0) { "number must be positive" } val start = if (signedValue[0] == 0.toByte()) { 1 } else { 0 } val bytes = Arrays.copyOfRange(signedValue, start, signedValue.size) return bytes.toHexString() diff --git a/util/src/test/kotlin/CryptoUtilTest.kt b/util/src/test/kotlin/CryptoUtilTest.kt @@ -17,18 +17,21 @@ * <http://www.gnu.org/licenses/> */ +import org.bouncycastle.asn1.edec.EdECObjectIdentifiers +import org.bouncycastle.asn1.x509.AlgorithmIdentifier +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.junit.Test -import tech.libeufin.util.CryptoUtil -import tech.libeufin.util.decodeHexString -import tech.libeufin.util.toHexString -import tech.libeufin.util.toUnsignedHexString +import tech.libeufin.util.* import java.math.BigInteger +import java.security.KeyFactory import java.security.KeyPairGenerator +import java.security.Security import java.security.interfaces.RSAPrivateCrtKey +import java.security.spec.KeySpec +import java.security.spec.X509EncodedKeySpec import javax.crypto.EncryptedPrivateKeyInfo import kotlin.test.assertEquals import kotlin.test.assertTrue - class CryptoUtilTest { @Test @@ -140,4 +143,20 @@ class CryptoUtilTest { assertEquals(expectedHash.toString(Charsets.UTF_8), pubHash.toHexString()) } + + @Test + fun importEdDSAPublicKeyTest() { + val givenEnc = "XZH3P6NF9DSG3BH0C082X38N2RVK1RV2H24KF76028QBKDM24BCG" + // import a public key + val spki = SubjectPublicKeyInfo(AlgorithmIdentifier( + EdECObjectIdentifiers.id_Ed25519), + base32ToBytes(givenEnc) + ) + val ks: KeySpec = X509EncodedKeySpec(spki.encoded) + val kpg = KeyFactory.getInstance( + "EdDSA", + org.bouncycastle.jce.provider.BouncyCastleProvider() + ) + kpg.generatePublic(ks) + } } \ No newline at end of file