gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated: refactor, partially implement order up


From: gnunet
Subject: [libeufin] branch master updated: refactor, partially implement order upload
Date: Fri, 08 Nov 2019 12:44:46 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new ebeb475  refactor, partially implement order upload
ebeb475 is described below

commit ebeb47583ae9f5c612bf3412545a4cddda574826
Author: Florian Dold <address@hidden>
AuthorDate: Fri Nov 8 12:42:20 2019 +0100

    refactor, partially implement order upload
---
 .idea/codeStyles/Project.xml                       |   1 -
 .../kotlin/tech/libeufin/sandbox/CryptoUtil.kt     | 236 +++++----
 .../src/main/kotlin/tech/libeufin/sandbox/DB.kt    |  50 +-
 .../kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt |  78 ++-
 .../sandbox/{Main.kt => EbicsProtocolBackend.kt}   | 463 +++++++----------
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  | 558 +--------------------
 sandbox/src/test/kotlin/CryptoUtilTest.kt          |   2 +-
 sandbox/src/test/kotlin/EbicsOrderUtilTest.kt      |  16 +
 8 files changed, 408 insertions(+), 996 deletions(-)

diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index e40fad6..1bec35e 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -5,7 +5,6 @@
     </JetCodeStyleSettings>
     <codeStyleSettings language="kotlin">
       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
-      <option name="WRAP_ON_TYPING" value="1" />
     </codeStyleSettings>
   </code_scheme>
 </component>
\ No newline at end of file
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt
index 93be1be..b3ca595 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt
@@ -21,10 +21,10 @@ 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.MessageDigest
 import java.security.interfaces.RSAPrivateCrtKey
 import java.security.interfaces.RSAPublicKey
 import java.security.spec.PKCS8EncodedKeySpec
@@ -32,20 +32,18 @@ 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.
- */
-data class RsaCrtKeyPair(val private: RSAPrivateCrtKey, val public: 
RSAPublicKey)
-
 /**
  * Helpers for dealing with cryptographic operations in EBICS / LibEuFin.
  */
-class CryptoUtil {
+object CryptoUtil {
+
+    /**
+     * RSA key pair.
+     */
+    data class RsaCrtKeyPair(val private: RSAPrivateCrtKey, val public: 
RSAPublicKey)
 
     class EncryptionResult(
         val encryptedTransactionKey: ByteArray,
@@ -53,116 +51,114 @@ class CryptoUtil {
         val encryptedData: ByteArray
     )
 
-    companion object {
-        private val bouncyCastleProvider = BouncyCastleProvider()
-
-        /**
-         * Load an RSA private key from its binary PKCS#8 encoding.
-         */
-        fun loadRsaPrivateKey(encodedPrivateKey: ByteArray): RSAPrivateCrtKey {
-            val spec = PKCS8EncodedKeySpec(encodedPrivateKey)
-            val priv = KeyFactory.getInstance("RSA").generatePrivate(spec)
-            if (priv !is RSAPrivateCrtKey)
-                throw Exception("wrong encoding")
-            return priv
-        }
-
-        /**
-         * Load an RSA public key from its binary X509 encoding.
-         */
-        fun loadRsaPublicKey(encodedPublicKey: ByteArray): RSAPublicKey {
-            val spec = X509EncodedKeySpec(encodedPublicKey)
-            val pub = KeyFactory.getInstance("RSA").generatePublic(spec)
-            if (pub !is RSAPublicKey)
-                throw Exception("wrong encoding")
-            return pub
-        }
-
-        /**
-         * Load an RSA public key from its binary X509 encoding.
-         */
-        fun getRsaPublicFromPrivate(rsaPrivateCrtKey: RSAPrivateCrtKey): 
RSAPublicKey {
-            val spec = RSAPublicKeySpec(rsaPrivateCrtKey.modulus, 
rsaPrivateCrtKey.publicExponent)
-            val pub = KeyFactory.getInstance("RSA").generatePublic(spec)
-            if (pub !is RSAPublicKey)
-                throw Exception("wrong encoding")
-            return pub
-        }
-
-        /**
-         * Generate a fresh RSA key pair.
-         *
-         * @param nbits size of the modulus in bits
-         */
-        fun generateRsaKeyPair(nbits: Int): RsaCrtKeyPair {
-            val gen = KeyPairGenerator.getInstance("RSA")
-            gen.initialize(nbits)
-            val pair = gen.genKeyPair()
-            val priv = pair.private
-            val pub = pair.public
-            if (priv !is RSAPrivateCrtKey)
-                throw Exception("key generation failed")
-            if (pub !is RSAPublicKey)
-                throw Exception("key generation failed")
-            return RsaCrtKeyPair(priv, pub)
-        }
-
-        /**
-         * Load an RSA public key from its components.
-         *
-         * @param exponent
-         * @param modulus
-         * @return key
-         */
-        fun loadRsaPublicKeyFromComponents(modulus: ByteArray, exponent: 
ByteArray): RSAPublicKey {
-            val modulusBigInt = BigInteger(1, modulus)
-            val exponentBigInt = BigInteger(1, exponent)
-
-            val keyFactory = KeyFactory.getInstance("RSA")
-            val tmp = RSAPublicKeySpec(modulusBigInt, exponentBigInt)
-            return keyFactory.generatePublic(tmp) as RSAPublicKey
-        }
-
-        /**
-         * 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().toHexString().toByteArray())
-            keyBytes.write(' '.toInt())
-            
keyBytes.writeBytes(publicKey.modulus.toByteArray().toHexString().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 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
-        }
+    private val bouncyCastleProvider = BouncyCastleProvider()
+
+    /**
+     * Load an RSA private key from its binary PKCS#8 encoding.
+     */
+    fun loadRsaPrivateKey(encodedPrivateKey: ByteArray): RSAPrivateCrtKey {
+        val spec = PKCS8EncodedKeySpec(encodedPrivateKey)
+        val priv = KeyFactory.getInstance("RSA").generatePrivate(spec)
+        if (priv !is RSAPrivateCrtKey)
+            throw Exception("wrong encoding")
+        return priv
+    }
+
+    /**
+     * Load an RSA public key from its binary X509 encoding.
+     */
+    fun loadRsaPublicKey(encodedPublicKey: ByteArray): RSAPublicKey {
+        val spec = X509EncodedKeySpec(encodedPublicKey)
+        val pub = KeyFactory.getInstance("RSA").generatePublic(spec)
+        if (pub !is RSAPublicKey)
+            throw Exception("wrong encoding")
+        return pub
+    }
+
+    /**
+     * Load an RSA public key from its binary X509 encoding.
+     */
+    fun getRsaPublicFromPrivate(rsaPrivateCrtKey: RSAPrivateCrtKey): 
RSAPublicKey {
+        val spec = RSAPublicKeySpec(rsaPrivateCrtKey.modulus, 
rsaPrivateCrtKey.publicExponent)
+        val pub = KeyFactory.getInstance("RSA").generatePublic(spec)
+        if (pub !is RSAPublicKey)
+            throw Exception("wrong encoding")
+        return pub
+    }
+
+    /**
+     * Generate a fresh RSA key pair.
+     *
+     * @param nbits size of the modulus in bits
+     */
+    fun generateRsaKeyPair(nbits: Int): RsaCrtKeyPair {
+        val gen = KeyPairGenerator.getInstance("RSA")
+        gen.initialize(nbits)
+        val pair = gen.genKeyPair()
+        val priv = pair.private
+        val pub = pair.public
+        if (priv !is RSAPrivateCrtKey)
+            throw Exception("key generation failed")
+        if (pub !is RSAPublicKey)
+            throw Exception("key generation failed")
+        return RsaCrtKeyPair(priv, pub)
+    }
+
+    /**
+     * Load an RSA public key from its components.
+     *
+     * @param exponent
+     * @param modulus
+     * @return key
+     */
+    fun loadRsaPublicKeyFromComponents(modulus: ByteArray, exponent: 
ByteArray): RSAPublicKey {
+        val modulusBigInt = BigInteger(1, modulus)
+        val exponentBigInt = BigInteger(1, exponent)
+
+        val keyFactory = KeyFactory.getInstance("RSA")
+        val tmp = RSAPublicKeySpec(modulusBigInt, exponentBigInt)
+        return keyFactory.generatePublic(tmp) as RSAPublicKey
+    }
+
+    /**
+     * 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().toHexString().toByteArray())
+        keyBytes.write(' '.toInt())
+        
keyBytes.writeBytes(publicKey.modulus.toByteArray().toHexString().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 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
     }
 }
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
index 8e1d678..b4cb2f6 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -20,7 +20,9 @@
 package tech.libeufin.sandbox
 
 import org.jetbrains.exposed.dao.*
-import org.jetbrains.exposed.sql.*
+import org.jetbrains.exposed.sql.Database
+import org.jetbrains.exposed.sql.ReferenceOption
+import org.jetbrains.exposed.sql.SchemaUtils
 import org.jetbrains.exposed.sql.transactions.transaction
 import java.sql.Blob
 
@@ -29,6 +31,7 @@ const val EBICS_HOST_ID_MAX_LENGTH = 10
 const val EBICS_USER_ID_MAX_LENGTH = 10
 const val EBICS_PARTNER_ID_MAX_LENGTH = 10
 const val EBICS_SYSTEM_ID_MAX_LENGTH = 10
+
 /**
  * All the states to give a subscriber.
  */
@@ -90,7 +93,7 @@ fun Blob.toByteArray(): ByteArray {
  * This table information *not* related to EBICS, for all
  * its customers.
  */
-object BankCustomersTable: IntIdTable() {
+object BankCustomersTable : IntIdTable() {
     // Customer ID is the default 'id' field provided by the constructor.
     val name = varchar("name", CUSTOMER_NAME_MAX_LENGTH).primaryKey()
     val ebicsSubscriber = reference("ebicsSubscriber", EbicsSubscribersTable)
@@ -118,6 +121,7 @@ object EbicsSubscriberPublicKeysTable : IntIdTable() {
  */
 class EbicsSubscriberPublicKeyEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : 
IntEntityClass<EbicsSubscriberPublicKeyEntity>(EbicsSubscriberPublicKeysTable)
+
     var rsaPublicKey by EbicsSubscriberPublicKeysTable.rsaPublicKey
     var state by EbicsSubscriberPublicKeysTable.state
 }
@@ -134,6 +138,7 @@ object EbicsHostsTable : IntIdTable() {
 
 class EbicsHostEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : IntEntityClass<EbicsHostEntity>(EbicsHostsTable)
+
     var hostId by EbicsHostsTable.hostID
     var ebicsVersion by EbicsHostsTable.ebicsVersion
     var signaturePrivateKey by EbicsHostsTable.signaturePrivateKey
@@ -203,6 +208,47 @@ class EbicsDownloadTransactionEntity(id: EntityID<String>) 
: Entity<String>(id)
 }
 
 
+object EbicsUploadTransactionsTable : IdTable<String>() {
+    override val id = text("transactionID").entityId()
+    val orderType = text("orderType")
+    val orderID = text("orderID")
+    val host = reference("host", EbicsHostsTable)
+    val subscriber = reference("subscriber", EbicsSubscribersTable)
+    val numSegments = integer("numSegments")
+    val lastSeenSegment = integer("lastSeenSegment")
+    val transactionKeyEnc = blob("transactionKeyEnc")
+}
+
+
+class EbicsUploadTransactionEntity(id: EntityID<String>) : Entity<String>(id) {
+    companion object : EntityClass<String, 
EbicsUploadTransactionEntity>(EbicsUploadTransactionsTable)
+
+    var orderType by EbicsUploadTransactionsTable.orderType
+    var orderID by EbicsUploadTransactionsTable.orderID
+    var host by EbicsHostEntity referencedOn EbicsUploadTransactionsTable.host
+    var subscriber by EbicsSubscriberEntity referencedOn 
EbicsUploadTransactionsTable.subscriber
+    var numSegments by EbicsUploadTransactionsTable.numSegments
+    var lastSeenSegment by EbicsUploadTransactionsTable.lastSeenSegment
+    var transactionKeyEnc by EbicsDownloadTransactionsTable.transactionKeyEnc
+}
+
+
+object EbicsUploadTransactionChunksTable : IdTable<String>() {
+    override val id =
+        
text("transactionID").entityId().references(EbicsUploadTransactionsTable.id, 
ReferenceOption.CASCADE)
+    val chunkIndex = integer("chunkIndex")
+    val chunkContent = blob("chunkContent")
+}
+
+
+class EbicsUploadTransactionChunkEntity(id : EntityID<String>): 
Entity<String>(id) {
+    companion object : EntityClass<String, 
EbicsUploadTransactionChunkEntity>(EbicsUploadTransactionChunksTable)
+
+    var chunkIndex by EbicsUploadTransactionChunksTable.chunkIndex
+    var chunkContent by EbicsUploadTransactionChunksTable.chunkContent
+}
+
+
 fun dbCreateTables() {
     Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = 
"org.h2.Driver")
 
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt
index 5652011..7fcd812 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt
@@ -19,6 +19,7 @@
 
 package tech.libeufin.sandbox
 
+import java.lang.IllegalArgumentException
 import java.security.SecureRandom
 import java.util.zip.DeflaterInputStream
 import java.util.zip.InflaterInputStream
@@ -26,36 +27,63 @@ import java.util.zip.InflaterInputStream
 /**
  * Helpers for dealing with order compression, encryption, decryption, 
chunking and re-assembly.
  */
-class EbicsOrderUtil private constructor() {
-    companion object {
-        inline fun <reified T> decodeOrderDataXml(encodedOrderData: 
ByteArray): T {
-            return InflaterInputStream(encodedOrderData.inputStream()).use {
-                val bytes = it.readAllBytes()
-                
XMLUtil.convertStringToJaxb<T>(bytes.toString(Charsets.UTF_8)).value
-            }
+object EbicsOrderUtil {
+    inline fun <reified T> decodeOrderDataXml(encodedOrderData: ByteArray): T {
+        return InflaterInputStream(encodedOrderData.inputStream()).use {
+            val bytes = it.readAllBytes()
+            
XMLUtil.convertStringToJaxb<T>(bytes.toString(Charsets.UTF_8)).value
         }
+    }
 
-        inline fun <reified T>encodeOrderDataXml(obj: T): ByteArray {
-            val bytes = XMLUtil.convertJaxbToString(obj).toByteArray()
-            return DeflaterInputStream(bytes.inputStream()).use {
-                it.readAllBytes()
-            }
+    inline fun <reified T> encodeOrderDataXml(obj: T): ByteArray {
+        val bytes = XMLUtil.convertJaxbToString(obj).toByteArray()
+        return DeflaterInputStream(bytes.inputStream()).use {
+            it.readAllBytes()
         }
+    }
 
-        fun generateTransactionId(): String {
-            val rng = SecureRandom()
-            val res = ByteArray(16)
-            rng.nextBytes(res)
-            return res.toHexString()
-        }
+    fun generateTransactionId(): String {
+        val rng = SecureRandom()
+        val res = ByteArray(16)
+        rng.nextBytes(res)
+        return res.toHexString()
+    }
+
+    /**
+     * Calculate the resulting size of base64-encoding data of the given 
length,
+     * including padding.
+     */
+    fun calculateBase64EncodedLength(dataLength: Int): Int {
+        val blocks = (dataLength + 3 - 1) / 3
+        return blocks * 4
+    }
+
+    fun checkOrderIDOverflow(n: Int): Boolean {
+        if (n <= 0)
+            throw IllegalArgumentException()
+        val base = 10 + 26
+        return n >= base * base
+    }
 
-        /**
-         * Calculate the resulting size of base64-encoding data of the given 
length,
-         * including padding.
-         */
-        fun calculateBase64EncodedLength(dataLength: Int): Int {
-            val blocks = (dataLength + 3 - 1) / 3
-            return blocks * 4
+    private fun getDigitChar(x: Int): Char {
+        if (x < 10) {
+            return '0' + x
         }
+        return 'A' + (x - 10)
+    }
+
+    fun computeOrderIDFromNumber(n: Int): String {
+        if (n <= 0)
+            throw IllegalArgumentException()
+        if (checkOrderIDOverflow(n))
+            throw IllegalArgumentException()
+        var ni = n
+        val base = 10 + 26
+        val x1 = ni % base
+        ni = ni / base
+        val x2 = ni % base
+        val c1 = getDigitChar(x1)
+        val c2 = getDigitChar(x2)
+        return String(charArrayOf('O', 'R', c2, c1))
     }
 }
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
similarity index 61%
copy from sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
copy to sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index 435a4e8..cd6a922 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -17,48 +17,28 @@
  * <http://www.gnu.org/licenses/>
  */
 
+
 package tech.libeufin.sandbox
 
 import io.ktor.application.ApplicationCall
-import io.ktor.application.ApplicationCallPipeline
-import io.ktor.application.call
-import io.ktor.application.install
-import io.ktor.features.CallLogging
-import io.ktor.features.ContentNegotiation
-import io.ktor.features.StatusPages
-import io.ktor.gson.gson
 import io.ktor.http.ContentType
 import io.ktor.http.HttpStatusCode
-import io.ktor.request.receive
 import io.ktor.request.receiveText
-import io.ktor.request.uri
 import io.ktor.response.respond
 import io.ktor.response.respondText
-import io.ktor.routing.get
-import io.ktor.routing.post
-import io.ktor.routing.routing
-import io.ktor.server.engine.embeddedServer
-import io.ktor.server.netty.Netty
 import org.apache.xml.security.binding.xmldsig.RSAKeyValueType
 import org.apache.xml.security.binding.xmldsig.SignatureType
-import org.jetbrains.exposed.sql.and
 import org.jetbrains.exposed.sql.transactions.transaction
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
 import org.w3c.dom.Document
 import tech.libeufin.schema.ebics_h004.*
 import tech.libeufin.schema.ebics_hev.HEVResponse
 import tech.libeufin.schema.ebics_hev.SystemReturnCodeType
 import tech.libeufin.schema.ebics_s001.SignaturePubKeyOrderData
 import java.math.BigInteger
-import java.security.interfaces.RSAPublicKey
-import java.text.DateFormat
 import java.util.*
 import java.util.zip.DeflaterInputStream
 import javax.sql.rowset.serial.SerialBlob
-import javax.xml.bind.JAXBContext
 
-val logger: Logger = LoggerFactory.getLogger("tech.libeufin.sandbox")
 
 open class EbicsRequestError(val errorText: String, val errorCode: String) :
     Exception("EBICS request management error: $errorText ($errorCode)")
@@ -68,9 +48,13 @@ class EbicsInvalidRequestError : 
EbicsRequestError("[EBICS_INVALID_REQUEST] Inva
 open class EbicsKeyManagementError(val errorText: String, val errorCode: 
String) :
     Exception("EBICS key management error: $errorText ($errorCode)")
 
-class EbicsInvalidXmlError : EbicsKeyManagementError("[EBICS_INVALID_XML]", 
"091010")
+private class EbicsInvalidXmlError : 
EbicsKeyManagementError("[EBICS_INVALID_XML]", "091010")
+
+private class EbicsInvalidOrderType : EbicsRequestError(
+    "[EBICS_UNSUPPORTED_ORDER_TYPE] Order type not supported",
+    "091005"
+)
 
-class EbicsInvalidOrderType : 
EbicsRequestError("[EBICS_UNSUPPORTED_ORDER_TYPE] Order type not supported", 
"091005")
 
 private suspend fun ApplicationCall.respondEbicsKeyManagement(
     errorText: String,
@@ -121,41 +105,6 @@ private suspend fun 
ApplicationCall.respondEbicsKeyManagement(
 }
 
 
-fun findEbicsSubscriber(partnerID: String, userID: String, systemID: String?): 
EbicsSubscriberEntity? {
-    return if (systemID == null) {
-        EbicsSubscriberEntity.find {
-            (EbicsSubscribersTable.partnerId eq partnerID) and 
(EbicsSubscribersTable.userId eq userID)
-        }
-    } else {
-        EbicsSubscriberEntity.find {
-            (EbicsSubscribersTable.partnerId eq partnerID) and
-                    (EbicsSubscribersTable.userId eq userID) and
-                    (EbicsSubscribersTable.systemId eq systemID)
-        }
-    }.firstOrNull()
-}
-
-
-data class Subscriber(
-    val partnerID: String,
-    val userID: String,
-    val systemID: String?
-)
-
-data class SubscriberKeys(
-    val authenticationPublicKey: RSAPublicKey,
-    val encryptionPublicKey: RSAPublicKey,
-    val signaturePublicKey: RSAPublicKey
-)
-
-
-data class EbicsHostInfo(
-    val hostID: String,
-    val encryptionPublicKey: RSAPublicKey,
-    val authenticationPublicKey: RSAPublicKey
-)
-
-
 private suspend fun ApplicationCall.handleEbicsHia(header: 
EbicsUnsecuredRequest.Header, orderData: ByteArray) {
     val keyObject = 
EbicsOrderUtil.decodeOrderDataXml<HIARequestOrderData>(orderData)
     val encPubXml = keyObject.encryptionPubKeyInfo.pubKeyValue.rsaKeyValue
@@ -214,7 +163,7 @@ private suspend fun ApplicationCall.handleEbicsIni(header: 
EbicsUnsecuredRequest
 }
 
 private suspend fun ApplicationCall.handleEbicsHpb(
-    ebicsHostInfo: EbicsHostInfo,
+    ebicsHostInfo: EbicsHostPublicInfo,
     requestDocument: Document,
     header: EbicsNpkdRequest.Header
 ) {
@@ -274,7 +223,7 @@ private suspend fun ApplicationCall.handleEbicsHpb(
 /**
  * Find the ebics host corresponding to the one specified in the header.
  */
-private fun ApplicationCall.ensureEbicsHost(requestHostID: String): 
EbicsHostInfo {
+private fun ApplicationCall.ensureEbicsHost(requestHostID: String): 
EbicsHostPublicInfo {
     return transaction {
         val ebicsHost = EbicsHostEntity.find { EbicsHostsTable.hostID eq 
requestHostID }.firstOrNull()
         if (ebicsHost == null) {
@@ -283,7 +232,7 @@ private fun ApplicationCall.ensureEbicsHost(requestHostID: 
String): EbicsHostInf
         }
         val encryptionPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.encryptionPrivateKey.toByteArray())
         val authenticationPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.authenticationPrivateKey.toByteArray())
-        EbicsHostInfo(
+        EbicsHostPublicInfo(
             requestHostID,
             CryptoUtil.getRsaPublicFromPrivate(encryptionPrivateKey),
             CryptoUtil.getRsaPublicFromPrivate(authenticationPrivateKey)
@@ -303,13 +252,6 @@ private suspend fun ApplicationCall.receiveEbicsXml(): 
Document {
 }
 
 
-inline fun <reified T> Document.toObject(): T {
-    val jc = JAXBContext.newInstance(T::class.java)
-    val m = jc.createUnmarshaller()
-    return m.unmarshal(this, T::class.java).value
-}
-
-
 fun handleEbicsHtd(): ByteArray {
     val htd = HTDResponseOrderData().apply {
         this.partnerInfo = HTDResponseOrderData.PartnerInfo().apply {
@@ -331,6 +273,24 @@ fun handleEbicsHtd(): ByteArray {
                             this.value = "INGDDEFFXXX"
                         }
                     )
+                },
+                HTDResponseOrderData.AccountInfo().apply {
+                    this.id = "glsdemo"
+                    this.accountHolder = "Mina Musterfrau"
+                    this.accountNumberList = listOf(
+                        HTDResponseOrderData.GeneralAccountNumber().apply {
+                            this.international = true
+                            this.value = "DE91430609670123123123"
+                        }
+                    )
+                    this.currency = "EUR"
+                    this.description = "glsdemoacct"
+                    this.bankCodeList = listOf(
+                        HTDResponseOrderData.GeneralBankCode().apply {
+                            this.international = true
+                            this.value = "GENODEM1GLS"
+                        }
+                    )
                 }
             )
             this.addressInfo = HTDResponseOrderData.AddressInfo().apply {
@@ -427,11 +387,6 @@ fun createEbicsResponseForDownloadInitializationPhase(
 }
 
 
-fun createEbicsResponseForDownloadTransferPhase() {
-
-}
-
-
 fun createEbicsResponseForDownloadReceiptPhase(transactionID: String, 
positiveAck: Boolean): EbicsResponse {
     return EbicsResponse().apply {
         this.version = "H004"
@@ -447,7 +402,7 @@ fun 
createEbicsResponseForDownloadReceiptPhase(transactionID: String, positiveAc
                     this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_DONE] 
Received positive receipt"
                     this.returnCode = "011000"
                 } else {
-                    this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_DONE] 
Received negative receipt"
+                    this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_SKIPPED] 
Received negative receipt"
                     this.returnCode = "011001"
                 }
             }
@@ -462,25 +417,34 @@ fun 
createEbicsResponseForDownloadReceiptPhase(transactionID: String, positiveAc
     }
 }
 
-
-private suspend fun ApplicationCall.handleEbicsDownloadInitialization() {
-
-}
-
-private suspend fun ApplicationCall.handleEbicsDownloadTransfer() {
-
-}
-
-private suspend fun ApplicationCall.handleEbicsDownloadReceipt() {
-
-}
-
-private suspend fun ApplicationCall.handleEbicsUploadInitialization() {
-
+fun createEbicsResponseForUploadInitializationPhase(transactionID: String, 
orderID: String): EbicsResponse {
+    return EbicsResponse().apply {
+        this.version = "H004"
+        this.revision = 1
+        this.header = EbicsResponse.Header().apply {
+            this.authenticate = true
+            this._static = EbicsResponse.StaticHeaderType().apply {
+                this.transactionID = transactionID
+            }
+            this.mutable = EbicsResponse.MutableHeaderType().apply {
+                this.transactionPhase = 
EbicsTypes.TransactionPhaseType.INITIALISATION
+                this.orderID = orderID
+                this.reportText = "[EBICS_OK] OK"
+                this.returnCode = "000000"
+            }
+        }
+        this.authSignature = SignatureType()
+        this.body = EbicsResponse.Body().apply {
+            this.returnCode = EbicsResponse.ReturnCode().apply {
+                this.authenticate = true
+                this.value = "000000"
+            }
+        }
+    }
 }
 
 
-private suspend fun ApplicationCall.ebicsweb() {
+suspend fun ApplicationCall.ebicsweb() {
     val requestDocument = receiveEbicsXml()
 
     logger.info("Processing ${requestDocument.documentElement.localName}")
@@ -523,114 +487,131 @@ private suspend fun ApplicationCall.ebicsweb() {
             println("ebicsRequest 
${XMLUtil.convertDomToString(requestDocument)}")
             val requestObject = requestDocument.toObject<EbicsRequest>()
             val staticHeader = requestObject.header.static
+            val requestedHostId = staticHeader.hostID
+
+            val responseXmlStr = transaction {
+                // Step 1 of 3:  Get information about the host and subscriber
+
+                val ebicsHost = EbicsHostEntity.find { EbicsHostsTable.hostID 
eq requestedHostId }.firstOrNull()
+                val requestTransactionID = 
requestObject.header.static.transactionID
+                var downloadTransaction: EbicsDownloadTransactionEntity? = null
+                var uploadTransaction: EbicsUploadTransactionEntity? = null
+                val subscriber = if (requestTransactionID != null) {
+                    downloadTransaction = 
EbicsDownloadTransactionEntity.findById(requestTransactionID)
+                    if (downloadTransaction != null) {
+                        downloadTransaction.subscriber
+                    } else {
+                        uploadTransaction = 
EbicsUploadTransactionEntity.findById(requestTransactionID)
+                        uploadTransaction?.subscriber
+                    }
+                } else {
+                    val partnerID = staticHeader.partnerID ?: throw 
EbicsInvalidRequestError()
+                    val userID = staticHeader.userID ?: throw 
EbicsInvalidRequestError()
+                    findEbicsSubscriber(partnerID, userID, 
staticHeader.systemID)
+                }
 
-            when (requestObject.header.mutable.transactionPhase) {
-                EbicsTypes.TransactionPhaseType.INITIALISATION -> {
-                    val partnerID = staticHeader.partnerID ?: throw 
EbicsInvalidXmlError()
-                    val userID = staticHeader.userID ?: throw 
EbicsInvalidXmlError()
-                    val respText = transaction {
-                        val subscriber =
-                            findEbicsSubscriber(partnerID, userID, 
staticHeader.systemID)
-                                ?: throw EbicsInvalidXmlError()
-                        val requestedHostId = 
requestObject.header.static.hostID
-                        val ebicsHost = EbicsHostEntity.find { 
EbicsHostsTable.hostID eq requestedHostId }.firstOrNull()
-                        if (ebicsHost == null)
-                            throw EbicsInvalidRequestError()
-                        val hostAuthPriv = CryptoUtil.loadRsaPrivateKey(
-                            ebicsHost.authenticationPrivateKey
-                                .toByteArray()
-                        )
-                        val clientAuthPub =
-                            
CryptoUtil.loadRsaPublicKey(subscriber.authenticationKey!!.rsaPublicKey.toByteArray())
-                        val clientEncPub =
-                            
CryptoUtil.loadRsaPublicKey(subscriber.encryptionKey!!.rsaPublicKey.toByteArray())
-                        val verifyResult = 
XMLUtil.verifyEbicsDocument(requestDocument, clientAuthPub)
-                        println("ebicsRequest verification result: 
$verifyResult")
-                        val transactionID = 
EbicsOrderUtil.generateTransactionId()
-                        val orderType = 
requestObject.header.static.orderDetails?.orderType
-
-                        val response = when (orderType) {
-                            "HTD" -> handleEbicsHtd()
-                            else -> throw EbicsInvalidXmlError()
-                        }
-
-                        val compressedResponse = 
DeflaterInputStream(response.inputStream()).use {
-                            it.readAllBytes()
-                        }
-
-                        val enc = 
CryptoUtil.encryptEbicsE002(compressedResponse, clientEncPub)
-                        val encodedResponse = 
Base64.getEncoder().encodeToString(enc.encryptedData)
-
-                        val segmentSize = 4096
-                        val totalSize = encodedResponse.length
-                        val numSegments = ((totalSize + segmentSize - 1) / 
segmentSize)
-
-                        println("inner response: " + 
response.toString(Charsets.UTF_8))
+                if (ebicsHost == null) throw EbicsInvalidRequestError()
+                if (subscriber == null) throw EbicsInvalidRequestError()
 
-                        println("total size: $totalSize")
-                        println("num segments: $numSegments")
+                val hostAuthPriv = CryptoUtil.loadRsaPrivateKey(
+                    ebicsHost.authenticationPrivateKey
+                        .toByteArray()
+                )
+                val clientAuthPub =
+                    
CryptoUtil.loadRsaPublicKey(subscriber.authenticationKey!!.rsaPublicKey.toByteArray())
+                val clientEncPub =
+                    
CryptoUtil.loadRsaPublicKey(subscriber.encryptionKey!!.rsaPublicKey.toByteArray())
+
+                // Step 2 of 3:  Validate the signature
+                val verifyResult = 
XMLUtil.verifyEbicsDocument(requestDocument, clientAuthPub)
+                if (!verifyResult) {
+                    throw EbicsInvalidRequestError()
+                }
 
-                        EbicsDownloadTransactionEntity.new(transactionID) {
-                            this.subscriber = subscriber
-                            this.host = ebicsHost
-                            this.orderType = orderType
-                            this.segmentSize = segmentSize
-                            this.transactionKeyEnc = 
SerialBlob(enc.encryptedTransactionKey)
-                            this.encodedResponse = encodedResponse
-                            this.numSegments = numSegments
-                            this.receiptReceived = false
+                val ebicsResponse: EbicsResponse = when 
(requestObject.header.mutable.transactionPhase) {
+                    EbicsTypes.TransactionPhaseType.INITIALISATION -> {
+                        val transactionID = 
EbicsOrderUtil.generateTransactionId()
+                        val orderType =
+                            
requestObject.header.static.orderDetails?.orderType ?: throw 
EbicsInvalidRequestError()
+                        if (staticHeader.numSegments == null) {
+                            val response = when (orderType) {
+                                "HTD" -> handleEbicsHtd()
+                                else -> throw EbicsInvalidXmlError()
+                            }
+
+                            val compressedResponse = 
DeflaterInputStream(response.inputStream()).use {
+                                it.readAllBytes()
+                            }
+
+                            val enc = 
CryptoUtil.encryptEbicsE002(compressedResponse, clientEncPub)
+                            val encodedResponse = 
Base64.getEncoder().encodeToString(enc.encryptedData)
+
+                            val segmentSize = 4096
+                            val totalSize = encodedResponse.length
+                            val numSegments = ((totalSize + segmentSize - 1) / 
segmentSize)
+
+                            EbicsDownloadTransactionEntity.new(transactionID) {
+                                this.subscriber = subscriber
+                                this.host = ebicsHost
+                                this.orderType = orderType
+                                this.segmentSize = segmentSize
+                                this.transactionKeyEnc = 
SerialBlob(enc.encryptedTransactionKey)
+                                this.encodedResponse = encodedResponse
+                                this.numSegments = numSegments
+                                this.receiptReceived = false
+                            }
+                            createEbicsResponseForDownloadInitializationPhase(
+                                transactionID,
+                                numSegments,
+                                segmentSize,
+                                enc,
+                                encodedResponse
+                            )
+                        } else {
+                            val oidn = subscriber.nextOrderID++
+                            if (EbicsOrderUtil.checkOrderIDOverflow(oidn)) 
throw NotImplementedError()
+                            val orderID = 
EbicsOrderUtil.computeOrderIDFromNumber(oidn)
+                            val signatureData = 
requestObject.body.dataTransfer?.signatureData
+                            if (signatureData != null) {
+                                println("signature data: 
${signatureData.toString(Charsets.UTF_8)}")
+                            }
+                            val numSegments =
+                                requestObject.header.static.numSegments ?: 
throw EbicsInvalidRequestError()
+                            val transactionKeyEnc =
+                                
requestObject.body.dataTransfer?.dataEncryptionInfo?.transactionKey
+                                    ?: throw EbicsInvalidRequestError()
+                            EbicsUploadTransactionEntity.new(transactionID) {
+                                this.host = ebicsHost
+                                this.subscriber = subscriber
+                                this.lastSeenSegment = 0
+                                this.orderType = orderType
+                                this.orderID = orderID
+                                this.numSegments = numSegments.toInt()
+                                this.transactionKeyEnc = 
SerialBlob(transactionKeyEnc)
+                            }
+                            
createEbicsResponseForUploadInitializationPhase(transactionID, orderID)
                         }
-
-                        val ebicsResponse = 
createEbicsResponseForDownloadInitializationPhase(
-                            transactionID,
-                            numSegments, segmentSize, enc, encodedResponse
-                        )
-                        val docText = 
XMLUtil.convertJaxbToString(ebicsResponse)
-                        val doc = XMLUtil.parseStringIntoDom(docText)
-                        XMLUtil.signEbicsDocument(doc, hostAuthPriv)
-                        val signedDoc = XMLUtil.convertDomToString(doc)
-                        println("response: $signedDoc")
-                        docText
                     }
-                    respondText(respText, ContentType.Application.Xml, 
HttpStatusCode.OK)
-                    return
-                }
-                EbicsTypes.TransactionPhaseType.TRANSFER -> {
-
-                }
-                EbicsTypes.TransactionPhaseType.RECEIPT -> {
-                    val respText = transaction {
-                        val requestedHostId = 
requestObject.header.static.hostID
-                        val ebicsHost = EbicsHostEntity.find { 
EbicsHostsTable.hostID eq requestedHostId }.firstOrNull()
-                        if (ebicsHost == null)
-                            throw EbicsInvalidRequestError()
-                        val hostAuthPriv = CryptoUtil.loadRsaPrivateKey(
-                            ebicsHost.authenticationPrivateKey
-                                .toByteArray()
-                        )
-                        val transactionID = 
requestObject.header.static.transactionID
-                        if (transactionID == null)
-                            throw EbicsInvalidRequestError()
-                        val downloadTransaction = 
EbicsDownloadTransactionEntity.findById(transactionID)
+                    EbicsTypes.TransactionPhaseType.TRANSFER -> {
+                        throw NotImplementedError()
+                    }
+                    EbicsTypes.TransactionPhaseType.RECEIPT -> {
+                        requestTransactionID ?: throw 
EbicsInvalidRequestError()
                         if (downloadTransaction == null)
                             throw EbicsInvalidRequestError()
-                        println("sending receipt for transaction ID 
$transactionID")
-                        val receiptCode = 
requestObject.body.transferReceipt?.receiptCode
-                        if (receiptCode == null)
-                            throw EbicsInvalidRequestError()
-                        val ebicsResponse = 
createEbicsResponseForDownloadReceiptPhase(transactionID, receiptCode == 0)
-                        val docText = 
XMLUtil.convertJaxbToString(ebicsResponse)
-                        val doc = XMLUtil.parseStringIntoDom(docText)
-                        XMLUtil.signEbicsDocument(doc, hostAuthPriv)
-                        val signedDoc = XMLUtil.convertDomToString(doc)
-                        println("response: $signedDoc")
-                        docText
+                        val receiptCode =
+                            requestObject.body.transferReceipt?.receiptCode ?: 
throw EbicsInvalidRequestError()
+                        
createEbicsResponseForDownloadReceiptPhase(requestTransactionID, receiptCode == 
0)
                     }
-                    respondText(respText, ContentType.Application.Xml, 
HttpStatusCode.OK)
-                    return
-
                 }
+                val docText = XMLUtil.convertJaxbToString(ebicsResponse)
+                val doc = XMLUtil.parseStringIntoDom(docText)
+                XMLUtil.signEbicsDocument(doc, hostAuthPriv)
+                val signedDoc = XMLUtil.convertDomToString(doc)
+                println("response: $signedDoc")
+                docText
             }
+            respondText(responseXmlStr, ContentType.Application.Xml, 
HttpStatusCode.OK)
         }
         else -> {
             /* Log to console and return "unknown type" */
@@ -642,109 +623,3 @@ private suspend fun ApplicationCall.ebicsweb() {
         }
     }
 }
-
-fun main() {
-    dbCreateTables()
-
-    transaction {
-        val pairA = CryptoUtil.generateRsaKeyPair(2048)
-        val pairB = CryptoUtil.generateRsaKeyPair(2048)
-        val pairC = CryptoUtil.generateRsaKeyPair(2048)
-        EbicsHostEntity.new {
-            hostId = "host01"
-            ebicsVersion = "H004"
-            authenticationPrivateKey = SerialBlob(pairA.private.encoded)
-            encryptionPrivateKey = SerialBlob(pairB.private.encoded)
-            signaturePrivateKey = SerialBlob(pairC.private.encoded)
-        }
-
-        EbicsSubscriberEntity.new {
-            partnerId = "PARTNER1"
-            userId = "USER1"
-            systemId = null
-            state = SubscriberState.NEW
-            nextOrderID = 1
-        }
-    }
-
-    val server = embeddedServer(Netty, port = 5000) {
-        install(CallLogging)
-        install(ContentNegotiation) {
-            gson {
-                setDateFormat(DateFormat.LONG)
-                setPrettyPrinting()
-            }
-        }
-        install(StatusPages) {
-            exception<Throwable> { cause ->
-                logger.error("Exception while handling '${call.request.uri}'", 
cause)
-                call.respondText("Internal server error.", 
ContentType.Text.Plain, HttpStatusCode.InternalServerError)
-            }
-        }
-        // TODO: add another intercept call that adds schema validation before 
the response is sent
-        intercept(ApplicationCallPipeline.Fallback) {
-            if (this.call.response.status() == null) {
-                call.respondText("Not found (no route matched).\n", 
ContentType.Text.Plain, HttpStatusCode.NotFound)
-                return@intercept finish()
-            }
-        }
-        routing {
-            //trace { logger.info(it.buildText()) }
-            get("/") {
-                call.respondText("Hello LibEuFin!\n", ContentType.Text.Plain)
-            }
-            get("/ebics/hosts") {
-                val ebicsHosts = transaction {
-                    EbicsHostEntity.all().map { it.hostId }
-                }
-                call.respond(EbicsHostsResponse(ebicsHosts))
-            }
-            post("/ebics/hosts") {
-                val req = call.receive<EbicsHostCreateRequest>()
-                transaction {
-                    EbicsHostEntity.new {
-                        this.ebicsVersion = req.ebicsVersion
-                        this.hostId = hostId
-                    }
-                }
-            }
-            get("/ebics/hosts/{id}") {
-                val resp = transaction {
-                    val host = EbicsHostEntity.find { EbicsHostsTable.hostID 
eq call.parameters["id"]!! }.firstOrNull()
-                    if (host == null) null
-                    else EbicsHostResponse(host.hostId, host.ebicsVersion)
-                }
-                if (resp == null) call.respond(
-                    HttpStatusCode.NotFound,
-                    SandboxError("host not found")
-                )
-                else call.respond(resp)
-            }
-            get("/ebics/subscribers") {
-                val subscribers = transaction {
-                    EbicsSubscriberEntity.all().map { it.id.value.toString() }
-                }
-                call.respond(EbicsSubscribersResponse(subscribers))
-            }
-            get("/ebics/subscribers/{id}") {
-                val resp = transaction {
-                    val id = call.parameters["id"]!!
-                    val subscriber = 
EbicsSubscriberEntity.findById(id.toInt())!!
-                    EbicsSubscriberResponse(
-                        id,
-                        subscriber.partnerId,
-                        subscriber.userId,
-                        subscriber.systemId,
-                        subscriber.state.name
-                    )
-                }
-                call.respond(resp)
-            }
-            post("/ebicsweb") {
-                call.ebicsweb()
-            }
-        }
-    }
-    logger.info("Up and running")
-    server.start(wait = true)
-}
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 435a4e8..4c70c90 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -19,7 +19,6 @@
 
 package tech.libeufin.sandbox
 
-import io.ktor.application.ApplicationCall
 import io.ktor.application.ApplicationCallPipeline
 import io.ktor.application.call
 import io.ktor.application.install
@@ -30,7 +29,6 @@ import io.ktor.gson.gson
 import io.ktor.http.ContentType
 import io.ktor.http.HttpStatusCode
 import io.ktor.request.receive
-import io.ktor.request.receiveText
 import io.ktor.request.uri
 import io.ktor.response.respond
 import io.ktor.response.respondText
@@ -39,86 +37,18 @@ import io.ktor.routing.post
 import io.ktor.routing.routing
 import io.ktor.server.engine.embeddedServer
 import io.ktor.server.netty.Netty
-import org.apache.xml.security.binding.xmldsig.RSAKeyValueType
-import org.apache.xml.security.binding.xmldsig.SignatureType
 import org.jetbrains.exposed.sql.and
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import org.w3c.dom.Document
-import tech.libeufin.schema.ebics_h004.*
-import tech.libeufin.schema.ebics_hev.HEVResponse
-import tech.libeufin.schema.ebics_hev.SystemReturnCodeType
-import tech.libeufin.schema.ebics_s001.SignaturePubKeyOrderData
-import java.math.BigInteger
 import java.security.interfaces.RSAPublicKey
 import java.text.DateFormat
-import java.util.*
-import java.util.zip.DeflaterInputStream
 import javax.sql.rowset.serial.SerialBlob
 import javax.xml.bind.JAXBContext
 
-val logger: Logger = LoggerFactory.getLogger("tech.libeufin.sandbox")
-
-open class EbicsRequestError(val errorText: String, val errorCode: String) :
-    Exception("EBICS request management error: $errorText ($errorCode)")
-
-class EbicsInvalidRequestError : EbicsRequestError("[EBICS_INVALID_REQUEST] 
Invalid request", "060102")
-
-open class EbicsKeyManagementError(val errorText: String, val errorCode: 
String) :
-    Exception("EBICS key management error: $errorText ($errorCode)")
-
-class EbicsInvalidXmlError : EbicsKeyManagementError("[EBICS_INVALID_XML]", 
"091010")
 
-class EbicsInvalidOrderType : 
EbicsRequestError("[EBICS_UNSUPPORTED_ORDER_TYPE] Order type not supported", 
"091005")
-
-private suspend fun ApplicationCall.respondEbicsKeyManagement(
-    errorText: String,
-    errorCode: String,
-    bankReturnCode: String,
-    dataTransfer: CryptoUtil.EncryptionResult? = null,
-    orderId: String? = null
-) {
-    val responseXml = EbicsKeyManagementResponse().apply {
-        version = "H004"
-        header = EbicsKeyManagementResponse.Header().apply {
-            authenticate = true
-            mutable = EbicsKeyManagementResponse.MutableHeaderType().apply {
-                reportText = errorText
-                returnCode = errorCode
-                if (orderId != null) {
-                    this.orderID = orderId
-                }
-            }
-            _static = EbicsKeyManagementResponse.EmptyStaticHeader()
-        }
-        body = EbicsKeyManagementResponse.Body().apply {
-            this.returnCode = EbicsKeyManagementResponse.ReturnCode().apply {
-                this.authenticate = true
-                this.value = bankReturnCode
-            }
-            if (dataTransfer != null) {
-                this.dataTransfer = 
EbicsKeyManagementResponse.DataTransfer().apply {
-                    this.dataEncryptionInfo = 
EbicsTypes.DataEncryptionInfo().apply {
-                        this.authenticate = true
-                        this.transactionKey = 
dataTransfer.encryptedTransactionKey
-                        this.encryptionPubKeyDigest = 
EbicsTypes.PubKeyDigest().apply {
-                            this.algorithm = 
"http://www.w3.org/2001/04/xmlenc#sha256";
-                            this.version = "E002"
-                            this.value = dataTransfer.pubKeyDigest
-                        }
-                    }
-                    this.orderData = 
EbicsKeyManagementResponse.OrderData().apply {
-                        this.value = dataTransfer.encryptedData
-                    }
-                }
-            }
-        }
-    }
-    val text = XMLUtil.convertJaxbToString(responseXml)
-    logger.info("responding with:\n${text}")
-    respondText(text, ContentType.Application.Xml, HttpStatusCode.OK)
-}
+val logger: Logger = LoggerFactory.getLogger("tech.libeufin.sandbox")
 
 
 fun findEbicsSubscriber(partnerID: String, userID: String, systemID: String?): 
EbicsSubscriberEntity? {
@@ -139,9 +69,11 @@ fun findEbicsSubscriber(partnerID: String, userID: String, 
systemID: String?): E
 data class Subscriber(
     val partnerID: String,
     val userID: String,
-    val systemID: String?
+    val systemID: String?,
+    val keys: SubscriberKeys
 )
 
+
 data class SubscriberKeys(
     val authenticationPublicKey: RSAPublicKey,
     val encryptionPublicKey: RSAPublicKey,
@@ -149,160 +81,13 @@ data class SubscriberKeys(
 )
 
 
-data class EbicsHostInfo(
+data class EbicsHostPublicInfo(
     val hostID: String,
     val encryptionPublicKey: RSAPublicKey,
     val authenticationPublicKey: RSAPublicKey
 )
 
 
-private suspend fun ApplicationCall.handleEbicsHia(header: 
EbicsUnsecuredRequest.Header, orderData: ByteArray) {
-    val keyObject = 
EbicsOrderUtil.decodeOrderDataXml<HIARequestOrderData>(orderData)
-    val encPubXml = keyObject.encryptionPubKeyInfo.pubKeyValue.rsaKeyValue
-    val authPubXml = keyObject.authenticationPubKeyInfo.pubKeyValue.rsaKeyValue
-    val encPub = CryptoUtil.loadRsaPublicKeyFromComponents(encPubXml.modulus, 
encPubXml.exponent)
-    val authPub = 
CryptoUtil.loadRsaPublicKeyFromComponents(authPubXml.modulus, 
authPubXml.exponent)
-
-    transaction {
-        val ebicsSubscriber = findEbicsSubscriber(header.static.partnerID, 
header.static.userID, header.static.systemID)
-        if (ebicsSubscriber == null) {
-            logger.warn("ebics subscriber not found")
-            throw EbicsInvalidRequestError()
-        }
-        ebicsSubscriber.authenticationKey = EbicsSubscriberPublicKeyEntity.new 
{
-            this.rsaPublicKey = SerialBlob(authPub.encoded)
-            state = KeyState.NEW
-        }
-        ebicsSubscriber.encryptionKey = EbicsSubscriberPublicKeyEntity.new {
-            this.rsaPublicKey = SerialBlob(encPub.encoded)
-            state = KeyState.NEW
-        }
-        ebicsSubscriber.state = when (ebicsSubscriber.state) {
-            SubscriberState.NEW -> SubscriberState.PARTIALLY_INITIALIZED_HIA
-            SubscriberState.PARTIALLY_INITIALIZED_INI -> 
SubscriberState.INITIALIZED
-            else -> ebicsSubscriber.state
-        }
-    }
-    respondEbicsKeyManagement("[EBICS_OK]", "000000", "000000")
-}
-
-
-private suspend fun ApplicationCall.handleEbicsIni(header: 
EbicsUnsecuredRequest.Header, orderData: ByteArray) {
-    val keyObject = 
EbicsOrderUtil.decodeOrderDataXml<SignaturePubKeyOrderData>(orderData)
-    val sigPubXml = keyObject.signaturePubKeyInfo.pubKeyValue.rsaKeyValue
-    val sigPub = CryptoUtil.loadRsaPublicKeyFromComponents(sigPubXml.modulus, 
sigPubXml.exponent)
-
-    transaction {
-        val ebicsSubscriber =
-            findEbicsSubscriber(header.static.partnerID, header.static.userID, 
header.static.systemID)
-        if (ebicsSubscriber == null) {
-            logger.warn("ebics subscriber ('${header.static.partnerID}' / 
'${header.static.userID}' / '${header.static.systemID}') not found")
-            throw EbicsInvalidRequestError()
-        }
-        ebicsSubscriber.signatureKey = EbicsSubscriberPublicKeyEntity.new {
-            this.rsaPublicKey = SerialBlob(sigPub.encoded)
-            state = KeyState.NEW
-        }
-        ebicsSubscriber.state = when (ebicsSubscriber.state) {
-            SubscriberState.NEW -> SubscriberState.PARTIALLY_INITIALIZED_INI
-            SubscriberState.PARTIALLY_INITIALIZED_HIA -> 
SubscriberState.INITIALIZED
-            else -> ebicsSubscriber.state
-        }
-    }
-    logger.info("Signature key inserted in database _and_ subscriber state 
changed accordingly")
-    respondEbicsKeyManagement("[EBICS_OK]", "000000", bankReturnCode = 
"000000", orderId = "OR01")
-}
-
-private suspend fun ApplicationCall.handleEbicsHpb(
-    ebicsHostInfo: EbicsHostInfo,
-    requestDocument: Document,
-    header: EbicsNpkdRequest.Header
-) {
-    val subscriberKeys = transaction {
-        val ebicsSubscriber =
-            findEbicsSubscriber(header.static.partnerID, header.static.userID, 
header.static.systemID)
-        if (ebicsSubscriber == null) {
-            throw EbicsInvalidRequestError()
-        }
-        if (ebicsSubscriber.state != SubscriberState.INITIALIZED) {
-            throw EbicsInvalidRequestError()
-        }
-        val authPubBlob = ebicsSubscriber.authenticationKey!!.rsaPublicKey
-        val encPubBlob = ebicsSubscriber.encryptionKey!!.rsaPublicKey
-        val sigPubBlob = ebicsSubscriber.signatureKey!!.rsaPublicKey
-        SubscriberKeys(
-            CryptoUtil.loadRsaPublicKey(authPubBlob.toByteArray()),
-            CryptoUtil.loadRsaPublicKey(encPubBlob.toByteArray()),
-            CryptoUtil.loadRsaPublicKey(sigPubBlob.toByteArray())
-        )
-    }
-    val validationResult =
-        XMLUtil.verifyEbicsDocument(requestDocument, 
subscriberKeys.authenticationPublicKey)
-    logger.info("validationResult: $validationResult")
-    if (!validationResult) {
-        throw EbicsKeyManagementError("invalid signature", "90000");
-    }
-    val hpbRespondeData = HPBResponseOrderData().apply {
-        this.authenticationPubKeyInfo = 
EbicsTypes.AuthenticationPubKeyInfoType().apply {
-            this.authenticationVersion = "X002"
-            this.pubKeyValue = EbicsTypes.PubKeyValueType().apply {
-                this.rsaKeyValue = RSAKeyValueType().apply {
-                    this.exponent = 
ebicsHostInfo.authenticationPublicKey.publicExponent.toByteArray()
-                    this.modulus = 
ebicsHostInfo.authenticationPublicKey.modulus.toByteArray()
-                }
-            }
-        }
-        this.encryptionPubKeyInfo = 
EbicsTypes.EncryptionPubKeyInfoType().apply {
-            this.encryptionVersion = "E002"
-            this.pubKeyValue = EbicsTypes.PubKeyValueType().apply {
-                this.rsaKeyValue = RSAKeyValueType().apply {
-                    this.exponent = 
ebicsHostInfo.encryptionPublicKey.publicExponent.toByteArray()
-                    this.modulus = 
ebicsHostInfo.encryptionPublicKey.modulus.toByteArray()
-                }
-            }
-        }
-        this.hostID = ebicsHostInfo.hostID
-    }
-
-    val compressedOrderData = 
EbicsOrderUtil.encodeOrderDataXml(hpbRespondeData)
-
-    val encryptionResult = CryptoUtil.encryptEbicsE002(compressedOrderData, 
subscriberKeys.encryptionPublicKey)
-
-    respondEbicsKeyManagement("[EBICS_OK]", "000000", "000000", 
encryptionResult, "OR01")
-}
-
-/**
- * Find the ebics host corresponding to the one specified in the header.
- */
-private fun ApplicationCall.ensureEbicsHost(requestHostID: String): 
EbicsHostInfo {
-    return transaction {
-        val ebicsHost = EbicsHostEntity.find { EbicsHostsTable.hostID eq 
requestHostID }.firstOrNull()
-        if (ebicsHost == null) {
-            logger.warn("client requested unknown HostID")
-            throw EbicsKeyManagementError("[EBICS_INVALID_HOST_ID]", "091011")
-        }
-        val encryptionPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.encryptionPrivateKey.toByteArray())
-        val authenticationPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.authenticationPrivateKey.toByteArray())
-        EbicsHostInfo(
-            requestHostID,
-            CryptoUtil.getRsaPublicFromPrivate(encryptionPrivateKey),
-            CryptoUtil.getRsaPublicFromPrivate(authenticationPrivateKey)
-        )
-    }
-}
-
-
-private suspend fun ApplicationCall.receiveEbicsXml(): Document {
-    val body: String = receiveText()
-    logger.debug("Data received: $body")
-    val requestDocument: Document? = XMLUtil.parseStringIntoDom(body)
-    if (requestDocument == null || 
(!XMLUtil.validateFromDom(requestDocument))) {
-        throw EbicsInvalidXmlError()
-    }
-    return requestDocument
-}
-
-
 inline fun <reified T> Document.toObject(): T {
     val jc = JAXBContext.newInstance(T::class.java)
     val m = jc.createUnmarshaller()
@@ -310,339 +95,6 @@ inline fun <reified T> Document.toObject(): T {
 }
 
 
-fun handleEbicsHtd(): ByteArray {
-    val htd = HTDResponseOrderData().apply {
-        this.partnerInfo = HTDResponseOrderData.PartnerInfo().apply {
-            this.accountInfoList = listOf(
-                HTDResponseOrderData.AccountInfo().apply {
-                    this.id = "acctid1"
-                    this.accountHolder = "Mina Musterfrau"
-                    this.accountNumberList = listOf(
-                        HTDResponseOrderData.GeneralAccountNumber().apply {
-                            this.international = true
-                            this.value = "DE21500105174751659277"
-                        }
-                    )
-                    this.currency = "EUR"
-                    this.description = "ACCT"
-                    this.bankCodeList = listOf(
-                        HTDResponseOrderData.GeneralBankCode().apply {
-                            this.international = true
-                            this.value = "INGDDEFFXXX"
-                        }
-                    )
-                }
-            )
-            this.addressInfo = HTDResponseOrderData.AddressInfo().apply {
-                this.name = "Foo"
-            }
-            this.bankInfo = HTDResponseOrderData.BankInfo().apply {
-                this.hostID = "host01"
-            }
-            this.orderInfoList = listOf(
-                HTDResponseOrderData.AuthOrderInfoType().apply {
-                    this.description = "foo"
-                    this.orderType = "C53"
-                    this.transferType = "Download"
-                },
-                HTDResponseOrderData.AuthOrderInfoType().apply {
-                    this.description = "foo"
-                    this.orderType = "C52"
-                    this.transferType = "Download"
-                },
-                HTDResponseOrderData.AuthOrderInfoType().apply {
-                    this.description = "foo"
-                    this.orderType = "CCC"
-                    this.transferType = "Upload"
-                }
-            )
-        }
-        this.userInfo = HTDResponseOrderData.UserInfo().apply {
-            this.name = "Some User"
-            this.userID = HTDResponseOrderData.UserIDType().apply {
-                this.status = 5
-                this.value = "USER1"
-            }
-            this.permissionList = listOf(
-                HTDResponseOrderData.UserPermission().apply {
-                    this.orderTypes = "C54 C53 C52 CCC"
-                }
-            )
-        }
-    }
-
-    val str = XMLUtil.convertJaxbToString(htd)
-    return str.toByteArray()
-}
-
-
-fun createEbicsResponseForDownloadInitializationPhase(
-    transactionID: String,
-    numSegments: Int,
-    segmentSize: Int,
-    enc: CryptoUtil.EncryptionResult,
-    encodedData: String
-): EbicsResponse {
-    return EbicsResponse().apply {
-        this.version = "H004"
-        this.revision = 1
-        this.header = EbicsResponse.Header().apply {
-            this.authenticate = true
-            this._static = EbicsResponse.StaticHeaderType().apply {
-                this.transactionID = transactionID
-                this.numSegments = BigInteger.valueOf(numSegments.toLong())
-            }
-            this.mutable = EbicsResponse.MutableHeaderType().apply {
-                this.transactionPhase = 
EbicsTypes.TransactionPhaseType.INITIALISATION
-                this.segmentNumber = EbicsResponse.SegmentNumber().apply {
-                    this.lastSegment = (numSegments == 1)
-                    this.value = BigInteger.valueOf(1)
-                }
-                this.reportText = "[EBICS_OK] OK"
-                this.returnCode = "000000"
-            }
-        }
-        this.authSignature = SignatureType()
-        this.body = EbicsResponse.Body().apply {
-            this.returnCode = EbicsResponse.ReturnCode().apply {
-                this.authenticate = true
-                this.value = "000000"
-            }
-            this.dataTransfer = EbicsResponse.DataTransferResponseType().apply 
{
-                this.dataEncryptionInfo = 
EbicsTypes.DataEncryptionInfo().apply {
-                    this.authenticate = true
-                    this.encryptionPubKeyDigest = 
EbicsTypes.PubKeyDigest().apply {
-                        this.algorithm = 
"http://www.w3.org/2001/04/xmlenc#sha256";
-                        this.version = "E002"
-                        this.value = enc.pubKeyDigest
-                    }
-                    this.transactionKey = enc.encryptedTransactionKey
-                }
-                this.orderData = EbicsResponse.OrderData().apply {
-                    this.value = encodedData.substring(0, 
Math.min(segmentSize, encodedData.length))
-                }
-            }
-        }
-    }
-}
-
-
-fun createEbicsResponseForDownloadTransferPhase() {
-
-}
-
-
-fun createEbicsResponseForDownloadReceiptPhase(transactionID: String, 
positiveAck: Boolean): EbicsResponse {
-    return EbicsResponse().apply {
-        this.version = "H004"
-        this.revision = 1
-        this.header = EbicsResponse.Header().apply {
-            this.authenticate = true
-            this._static = EbicsResponse.StaticHeaderType().apply {
-                this.transactionID = transactionID
-            }
-            this.mutable = EbicsResponse.MutableHeaderType().apply {
-                this.transactionPhase = EbicsTypes.TransactionPhaseType.RECEIPT
-                if (positiveAck) {
-                    this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_DONE] 
Received positive receipt"
-                    this.returnCode = "011000"
-                } else {
-                    this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_DONE] 
Received negative receipt"
-                    this.returnCode = "011001"
-                }
-            }
-        }
-        this.authSignature = SignatureType()
-        this.body = EbicsResponse.Body().apply {
-            this.returnCode = EbicsResponse.ReturnCode().apply {
-                this.authenticate = true
-                this.value = "000000"
-            }
-        }
-    }
-}
-
-
-private suspend fun ApplicationCall.handleEbicsDownloadInitialization() {
-
-}
-
-private suspend fun ApplicationCall.handleEbicsDownloadTransfer() {
-
-}
-
-private suspend fun ApplicationCall.handleEbicsDownloadReceipt() {
-
-}
-
-private suspend fun ApplicationCall.handleEbicsUploadInitialization() {
-
-}
-
-
-private suspend fun ApplicationCall.ebicsweb() {
-    val requestDocument = receiveEbicsXml()
-
-    logger.info("Processing ${requestDocument.documentElement.localName}")
-
-    when (requestDocument.documentElement.localName) {
-        "ebicsUnsecuredRequest" -> {
-            val requestObject = 
requestDocument.toObject<EbicsUnsecuredRequest>()
-            logger.info("Serving a 
${requestObject.header.static.orderDetails.orderType} request")
-
-            val orderData = requestObject.body.dataTransfer.orderData.value
-            val header = requestObject.header
-
-            when (header.static.orderDetails.orderType) {
-                "INI" -> handleEbicsIni(header, orderData)
-                "HIA" -> handleEbicsHia(header, orderData)
-                else -> throw EbicsInvalidXmlError()
-            }
-        }
-        "ebicsHEVRequest" -> {
-            val hevResponse = HEVResponse().apply {
-                this.systemReturnCode = SystemReturnCodeType().apply {
-                    this.reportText = "[EBICS_OK]"
-                    this.returnCode = "000000"
-                }
-                this.versionNumber = 
listOf(HEVResponse.VersionNumber.create("H004", "02.50"))
-            }
-
-            val strResp = XMLUtil.convertJaxbToString(hevResponse)
-            respondText(strResp, ContentType.Application.Xml, 
HttpStatusCode.OK)
-        }
-        "ebicsNoPubKeyDigestsRequest" -> {
-            val requestObject = requestDocument.toObject<EbicsNpkdRequest>()
-            val hostInfo = ensureEbicsHost(requestObject.header.static.hostID)
-            when (requestObject.header.static.orderDetails.orderType) {
-                "HPB" -> handleEbicsHpb(hostInfo, requestDocument, 
requestObject.header)
-                else -> throw EbicsInvalidXmlError()
-            }
-        }
-        "ebicsRequest" -> {
-            println("ebicsRequest 
${XMLUtil.convertDomToString(requestDocument)}")
-            val requestObject = requestDocument.toObject<EbicsRequest>()
-            val staticHeader = requestObject.header.static
-
-            when (requestObject.header.mutable.transactionPhase) {
-                EbicsTypes.TransactionPhaseType.INITIALISATION -> {
-                    val partnerID = staticHeader.partnerID ?: throw 
EbicsInvalidXmlError()
-                    val userID = staticHeader.userID ?: throw 
EbicsInvalidXmlError()
-                    val respText = transaction {
-                        val subscriber =
-                            findEbicsSubscriber(partnerID, userID, 
staticHeader.systemID)
-                                ?: throw EbicsInvalidXmlError()
-                        val requestedHostId = 
requestObject.header.static.hostID
-                        val ebicsHost = EbicsHostEntity.find { 
EbicsHostsTable.hostID eq requestedHostId }.firstOrNull()
-                        if (ebicsHost == null)
-                            throw EbicsInvalidRequestError()
-                        val hostAuthPriv = CryptoUtil.loadRsaPrivateKey(
-                            ebicsHost.authenticationPrivateKey
-                                .toByteArray()
-                        )
-                        val clientAuthPub =
-                            
CryptoUtil.loadRsaPublicKey(subscriber.authenticationKey!!.rsaPublicKey.toByteArray())
-                        val clientEncPub =
-                            
CryptoUtil.loadRsaPublicKey(subscriber.encryptionKey!!.rsaPublicKey.toByteArray())
-                        val verifyResult = 
XMLUtil.verifyEbicsDocument(requestDocument, clientAuthPub)
-                        println("ebicsRequest verification result: 
$verifyResult")
-                        val transactionID = 
EbicsOrderUtil.generateTransactionId()
-                        val orderType = 
requestObject.header.static.orderDetails?.orderType
-
-                        val response = when (orderType) {
-                            "HTD" -> handleEbicsHtd()
-                            else -> throw EbicsInvalidXmlError()
-                        }
-
-                        val compressedResponse = 
DeflaterInputStream(response.inputStream()).use {
-                            it.readAllBytes()
-                        }
-
-                        val enc = 
CryptoUtil.encryptEbicsE002(compressedResponse, clientEncPub)
-                        val encodedResponse = 
Base64.getEncoder().encodeToString(enc.encryptedData)
-
-                        val segmentSize = 4096
-                        val totalSize = encodedResponse.length
-                        val numSegments = ((totalSize + segmentSize - 1) / 
segmentSize)
-
-                        println("inner response: " + 
response.toString(Charsets.UTF_8))
-
-                        println("total size: $totalSize")
-                        println("num segments: $numSegments")
-
-                        EbicsDownloadTransactionEntity.new(transactionID) {
-                            this.subscriber = subscriber
-                            this.host = ebicsHost
-                            this.orderType = orderType
-                            this.segmentSize = segmentSize
-                            this.transactionKeyEnc = 
SerialBlob(enc.encryptedTransactionKey)
-                            this.encodedResponse = encodedResponse
-                            this.numSegments = numSegments
-                            this.receiptReceived = false
-                        }
-
-                        val ebicsResponse = 
createEbicsResponseForDownloadInitializationPhase(
-                            transactionID,
-                            numSegments, segmentSize, enc, encodedResponse
-                        )
-                        val docText = 
XMLUtil.convertJaxbToString(ebicsResponse)
-                        val doc = XMLUtil.parseStringIntoDom(docText)
-                        XMLUtil.signEbicsDocument(doc, hostAuthPriv)
-                        val signedDoc = XMLUtil.convertDomToString(doc)
-                        println("response: $signedDoc")
-                        docText
-                    }
-                    respondText(respText, ContentType.Application.Xml, 
HttpStatusCode.OK)
-                    return
-                }
-                EbicsTypes.TransactionPhaseType.TRANSFER -> {
-
-                }
-                EbicsTypes.TransactionPhaseType.RECEIPT -> {
-                    val respText = transaction {
-                        val requestedHostId = 
requestObject.header.static.hostID
-                        val ebicsHost = EbicsHostEntity.find { 
EbicsHostsTable.hostID eq requestedHostId }.firstOrNull()
-                        if (ebicsHost == null)
-                            throw EbicsInvalidRequestError()
-                        val hostAuthPriv = CryptoUtil.loadRsaPrivateKey(
-                            ebicsHost.authenticationPrivateKey
-                                .toByteArray()
-                        )
-                        val transactionID = 
requestObject.header.static.transactionID
-                        if (transactionID == null)
-                            throw EbicsInvalidRequestError()
-                        val downloadTransaction = 
EbicsDownloadTransactionEntity.findById(transactionID)
-                        if (downloadTransaction == null)
-                            throw EbicsInvalidRequestError()
-                        println("sending receipt for transaction ID 
$transactionID")
-                        val receiptCode = 
requestObject.body.transferReceipt?.receiptCode
-                        if (receiptCode == null)
-                            throw EbicsInvalidRequestError()
-                        val ebicsResponse = 
createEbicsResponseForDownloadReceiptPhase(transactionID, receiptCode == 0)
-                        val docText = 
XMLUtil.convertJaxbToString(ebicsResponse)
-                        val doc = XMLUtil.parseStringIntoDom(docText)
-                        XMLUtil.signEbicsDocument(doc, hostAuthPriv)
-                        val signedDoc = XMLUtil.convertDomToString(doc)
-                        println("response: $signedDoc")
-                        docText
-                    }
-                    respondText(respText, ContentType.Application.Xml, 
HttpStatusCode.OK)
-                    return
-
-                }
-            }
-        }
-        else -> {
-            /* Log to console and return "unknown type" */
-            logger.info("Unknown message, just logging it!")
-            respond(
-                HttpStatusCode.NotImplemented,
-                SandboxError("Not Implemented")
-            )
-        }
-    }
-}
-
 fun main() {
     dbCreateTables()
 
diff --git a/sandbox/src/test/kotlin/CryptoUtilTest.kt 
b/sandbox/src/test/kotlin/CryptoUtilTest.kt
index a2b0901..0846836 100644
--- a/sandbox/src/test/kotlin/CryptoUtilTest.kt
+++ b/sandbox/src/test/kotlin/CryptoUtilTest.kt
@@ -53,7 +53,7 @@ class CryptoUtilTest {
         val encodedPriv = keyPair.private.encoded
         val encodedPub = keyPair.public.encoded
         val otherKeyPair =
-            RsaCrtKeyPair(CryptoUtil.loadRsaPrivateKey(encodedPriv), 
CryptoUtil.loadRsaPublicKey(encodedPub))
+            
CryptoUtil.RsaCrtKeyPair(CryptoUtil.loadRsaPrivateKey(encodedPriv), 
CryptoUtil.loadRsaPublicKey(encodedPub))
         assertEquals(keyPair.private, otherKeyPair.private)
         assertEquals(keyPair.public, otherKeyPair.public)
     }
diff --git a/sandbox/src/test/kotlin/EbicsOrderUtilTest.kt 
b/sandbox/src/test/kotlin/EbicsOrderUtilTest.kt
new file mode 100644
index 0000000..c35794e
--- /dev/null
+++ b/sandbox/src/test/kotlin/EbicsOrderUtilTest.kt
@@ -0,0 +1,16 @@
+package tech.libeufin.sandbox
+
+import org.junit.Test
+import kotlin.test.assertEquals
+
+
+class EbicsOrderUtilTest {
+
+    @Test
+    fun testComputeOrderIDFromNumber() {
+        assertEquals("OR01", EbicsOrderUtil.computeOrderIDFromNumber(1))
+        assertEquals("OR0A", EbicsOrderUtil.computeOrderIDFromNumber(10))
+        assertEquals("OR10", EbicsOrderUtil.computeOrderIDFromNumber(36))
+        assertEquals("OR11", EbicsOrderUtil.computeOrderIDFromNumber(37))
+    }
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]