libeufin

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

commit 855c0bb1fc8a9287320fa161552a85bac9acb98a
parent e30e4700e165ec5c38d21a9619b4f24ef8f0f21a
Author: Florian Dold <florian.dold@gmail.com>
Date:   Mon,  4 Nov 2019 12:39:15 +0100

implement and test EBICS E002

Diffstat:
Msandbox/src/main/kotlin/CryptoUtil.kt | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msandbox/src/test/kotlin/CryptoUtilTest.kt | 7+++++--
2 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/sandbox/src/main/kotlin/CryptoUtil.kt b/sandbox/src/main/kotlin/CryptoUtil.kt @@ -20,12 +20,11 @@ package tech.libeufin.sandbox import org.bouncycastle.jce.provider.BouncyCastleProvider +import java.io.ByteArrayOutputStream import java.lang.Exception import java.math.BigInteger import java.security.KeyFactory import java.security.KeyPairGenerator -import java.security.PrivateKey -import java.security.PublicKey import java.security.interfaces.RSAPrivateCrtKey import java.security.interfaces.RSAPublicKey import java.security.spec.PKCS8EncodedKeySpec @@ -33,6 +32,15 @@ import java.security.spec.RSAPublicKeySpec import java.security.spec.X509EncodedKeySpec import javax.crypto.Cipher import javax.crypto.KeyGenerator +import java.security.MessageDigest +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec + + + + + + /** * RSA key pair. @@ -120,15 +128,52 @@ class CryptoUtil { return keyFactory.generatePublic(tmp) as RSAPublicKey } - fun encryptEbicsE002(data: ByteArray, signingPrivateKey: RSAPrivateCrtKey) { - val prov = BouncyCastleProvider() + /** + * Hash an RSA public key according to the EBICS standard (EBICS 2.5: 4.4.1.2.3). + */ + fun getEbicsPublicKeyHash(publicKey: RSAPublicKey): ByteArray { + val keyBytes = ByteArrayOutputStream() + keyBytes.writeBytes(publicKey.publicExponent.toByteArray()) + keyBytes.write(' '.toInt()) + keyBytes.writeBytes(publicKey.modulus.toByteArray()) + val digest = MessageDigest.getInstance("SHA-256") + return digest.digest(keyBytes.toByteArray()) + } + + /** + * Encrypt data according to the EBICS E002 encryption process. + */ + fun encryptEbicsE002(data: ByteArray, encryptionPublicKey: RSAPublicKey): EncryptionResult { val keygen = KeyGenerator.getInstance("AES", bouncyCastleProvider) keygen.init(128) - val transportKey = keygen.generateKey() + val transactionKey = keygen.generateKey() + val symmetricCipher = Cipher.getInstance("AES/CBC/X9.23Padding", bouncyCastleProvider) + val ivParameterSpec = IvParameterSpec(ByteArray(16)) + symmetricCipher.init(Cipher.ENCRYPT_MODE, transactionKey, ivParameterSpec) + val encryptedData = symmetricCipher.doFinal(data) + val asymmetricCipher = Cipher.getInstance("RSA/None/PKCS1Padding", bouncyCastleProvider) + asymmetricCipher.init(Cipher.ENCRYPT_MODE, encryptionPublicKey) + val encryptedTransactionKey = asymmetricCipher.doFinal(transactionKey.encoded) + val pubKeyDigest = getEbicsPublicKeyHash(encryptionPublicKey) + return EncryptionResult(encryptedTransactionKey, pubKeyDigest, encryptedData) + } + + fun decryptEbicsE002(enc: EncryptionResult, privateKey: RSAPrivateCrtKey): ByteArray { + val asymmetricCipher = Cipher.getInstance("RSA/None/PKCS1Padding", bouncyCastleProvider) + asymmetricCipher.init(Cipher.DECRYPT_MODE, privateKey) + val transactionKeyBytes = asymmetricCipher.doFinal(enc.encryptedTransactionKey) + val secretKeySpec = SecretKeySpec(transactionKeyBytes, "AES") + val symmetricCipher = Cipher.getInstance("AES/CBC/X9.23Padding", bouncyCastleProvider) + val ivParameterSpec = IvParameterSpec(ByteArray(16)) + symmetricCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) + val data = symmetricCipher.doFinal(enc.encryptedData) + return data + } - val cipher = Cipher.getInstance("AES/CBC/X9.23Padding", bouncyCastleProvider) - cipher.init(Cipher.ENCRYPT_MODE, transportKey) - val encryptedData = cipher.doFinal(data) + fun ByteArray.toHexString() : String { + return this.joinToString("") { + java.lang.String.format("%02x", it) + } } } } diff --git a/sandbox/src/test/kotlin/CryptoUtilTest.kt b/sandbox/src/test/kotlin/CryptoUtilTest.kt @@ -24,6 +24,7 @@ import java.security.KeyPairGenerator import java.security.interfaces.RSAPrivateCrtKey import kotlin.test.assertEquals import kotlin.test.assertTrue +import kotlin.collections.contentEquals class CryptoUtilTest { @@ -59,8 +60,10 @@ class CryptoUtilTest { @Test fun testEbicsE002() { - val data = "Hello, World!" + val data = "Hello, World!".toByteArray() val keyPair = CryptoUtil.generateRsaKeyPair(1024) - CryptoUtil.encryptEbicsE002(data.toByteArray(), keyPair.private) + val enc = CryptoUtil.encryptEbicsE002(data, keyPair.public) + val dec = CryptoUtil.decryptEbicsE002(enc, keyPair.private) + assertTrue(data.contentEquals(dec)) } } \ No newline at end of file