summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2024-03-06 09:55:03 +0100
committerAntoine A <>2024-03-06 09:55:03 +0100
commit9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47 (patch)
tree871fac85827e18e240e38dc3bb15b57a0ba3fda0
parent73c011ab2f5679bd1fb966318c53790097241540 (diff)
downloadlibeufin-9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47.tar.gz
libeufin-9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47.tar.bz2
libeufin-9af4fd9bcb338f20e75254f1aaad9ee7b1c0df47.zip
Improve password crypto and TAN documentation
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt4
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt (renamed from bank/src/main/kotlin/tech/libeufin/bank/Tan.kt)20
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt5
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt9
-rw-r--r--common/src/main/kotlin/crypto/password.kt73
-rw-r--r--common/src/main/kotlin/crypto/utils.kt (renamed from common/src/main/kotlin/CryptoUtil.kt)34
-rw-r--r--common/src/main/kotlin/strings.kt9
-rw-r--r--common/src/test/kotlin/CryptoUtilTest.kt5
-rw-r--r--ebics/src/main/kotlin/Ebics.kt2
-rw-r--r--ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt2
-rw-r--r--ebics/src/main/kotlin/ebics_h004/EbicsResponse.kt2
-rw-r--r--ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt2
-rw-r--r--ebics/src/main/kotlin/ebics_h005/Ebics3Response.kt2
-rw-r--r--ebics/src/test/kotlin/EbicsMessagesTest.kt2
-rw-r--r--ebics/src/test/kotlin/SignatureDataTest.kt2
-rw-r--r--ebics/src/test/kotlin/XmlUtilTest.kt2
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt1
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt2
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt1
-rw-r--r--nexus/src/test/kotlin/CliTest.kt2
-rw-r--r--nexus/src/test/kotlin/Keys.kt2
-rw-r--r--nexus/src/test/kotlin/MySerializers.kt2
22 files changed, 126 insertions, 59 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
index 2bda3a43..4b6a6e53 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -318,7 +318,7 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
requireAdmin = !ctx.allowAccountDeletion
) {
delete("/accounts/{USERNAME}") {
- val challenge = call.challenge(db, Operation.account_delete)
+ val challenge = call.checkChallenge(db, Operation.account_delete)
// Not deleting reserved names.
if (RESERVED_ACCOUNTS.contains(username))
@@ -511,7 +511,7 @@ private fun Routing.coreBankWithdrawalApi(db: Database, ctx: BankConfig) {
}
post("/accounts/{USERNAME}/withdrawals/{withdrawal_id}/confirm") {
val id = call.uuidParameter("withdrawal_id")
- val challenge = call.challenge(db, Operation.withdrawal)
+ val challenge = call.checkChallenge(db, Operation.withdrawal)
when (db.withdrawal.confirm(username, id, Instant.now(), challenge != null)) {
WithdrawalConfirmationResult.UnknownOperation -> throw notFound(
"Withdrawal operation $id not found",
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Tan.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt
index eadddc29..f0b346ca 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Tan.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/auth/Tan.kt
@@ -1,6 +1,6 @@
/*
* This file is part of LibEuFin.
- * Copyright (C) 2023 Stanisci and Dold.
+ * Copyright (C) 2023-2024 Stanisci and Dold.
* LibEuFin is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -30,7 +30,13 @@ import java.security.SecureRandom
import java.text.DecimalFormat
import java.time.Instant
-
+/**
+ * Generate a TAN challenge for an [op] request with [body] and
+ * respond to the HTTP request with a TAN challenge.
+ *
+ * If [channel] and [info] are present, they will be used
+ * to send the TAN code, otherwise defaults will be used.
+ */
suspend inline fun <reified B> ApplicationCall.respondChallenge(
db: Database,
op: Operation,
@@ -57,6 +63,10 @@ suspend inline fun <reified B> ApplicationCall.respondChallenge(
)
}
+/**
+ * Retrieve a confirmed challenge and its body for [op] from the database
+ * if the challenge header is defined, otherwise extract the HTTP body.
+ */
suspend inline fun <reified B> ApplicationCall.receiveChallenge(
db: Database,
op: Operation
@@ -70,7 +80,10 @@ suspend inline fun <reified B> ApplicationCall.receiveChallenge(
}
}
-suspend fun ApplicationCall.challenge(
+/**
+ * Retrieve a confirmed challenge body for [op] if the challenge header is defined
+ */
+suspend fun ApplicationCall.checkChallenge(
db: Database,
op: Operation
): Challenge? {
@@ -86,6 +99,7 @@ object Tan {
private val CODE_FORMAT = DecimalFormat("00000000")
private val SECURE_RNG = SecureRandom()
+ /** Generate a secure random TAN code */
fun genCode(): String {
val rand = SECURE_RNG.nextInt(100000000)
val code = CODE_FORMAT.format(rand)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt b/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt
index c70627e7..7e8f4aac 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/auth/auth.kt
@@ -28,6 +28,7 @@ import io.ktor.util.pipeline.*
import tech.libeufin.bank.*
import tech.libeufin.bank.db.Database
import tech.libeufin.common.*
+import tech.libeufin.common.crypto.*
import java.time.Instant
/** Used to store if the currently authenticated user is admin */
@@ -134,13 +135,13 @@ private suspend fun ApplicationCall.authenticateBankRequest(db: Database, requir
* Returns the authenticated customer login
*/
private suspend fun doBasicAuth(db: Database, encoded: String): String {
- val decoded = String(base64ToBytes(encoded), Charsets.UTF_8)
+ val decoded = String(encoded.decodeBase64(), Charsets.UTF_8)
val (login, plainPassword) = decoded.splitOnce(":") ?: throw badRequest(
"Malformed Basic auth credentials found in the Authorization header",
TalerErrorCode.GENERIC_HTTP_HEADERS_MALFORMED
)
val hash = db.account.passwordHash(login) ?: throw unauthorized("Unknown account")
- if (!CryptoUtil.checkpw(plainPassword, hash)) throw unauthorized("Bad password")
+ if (!PwCrypto.checkpw(plainPassword, hash)) throw unauthorized("Bad password")
return login
}
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
index a23d34d5..c4c5054c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
@@ -21,6 +21,7 @@ package tech.libeufin.bank.db
import tech.libeufin.bank.*
import tech.libeufin.common.*
+import tech.libeufin.common.crypto.*
import java.time.Instant
/** Data access logic for accounts */
@@ -78,7 +79,7 @@ class AccountDAO(private val db: Database) {
setString(9, tanChannel?.name)
setString(10, login)
oneOrNull {
- CryptoUtil.checkpw(password, it.getString(1)) && it.getBoolean(2)
+ PwCrypto.checkpw(password, it.getString(1)) && it.getBoolean(2)
}
}
@@ -118,7 +119,7 @@ class AccountDAO(private val db: Database) {
"""
).run {
setString(1, login)
- setString(2, CryptoUtil.hashpw(password))
+ setString(2, PwCrypto.hashpw(password))
setString(3, name)
setString(4, email)
setString(5, phone)
@@ -392,13 +393,13 @@ class AccountDAO(private val db: Database) {
}
if (tanRequired) {
AccountPatchAuthResult.TanRequired
- } else if (oldPw != null && !CryptoUtil.checkpw(oldPw, currentPwh)) {
+ } else if (oldPw != null && !PwCrypto.checkpw(oldPw, currentPwh)) {
AccountPatchAuthResult.OldPasswordMismatch
} else {
val stmt = conn.prepareStatement("""
UPDATE customers SET password_hash=? where login=?
""")
- stmt.setString(1, CryptoUtil.hashpw(newPw))
+ stmt.setString(1, PwCrypto.hashpw(newPw))
stmt.setString(2, login)
stmt.executeUpdateCheck()
AccountPatchAuthResult.Success
diff --git a/common/src/main/kotlin/crypto/password.kt b/common/src/main/kotlin/crypto/password.kt
new file mode 100644
index 00000000..2dd8af07
--- /dev/null
+++ b/common/src/main/kotlin/crypto/password.kt
@@ -0,0 +1,73 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2024 Taler Systems S.A.
+
+ * LibEuFin is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3, or
+ * (at your option) any later version.
+
+ * LibEuFin is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
+ * Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public
+ * License along with LibEuFin; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>
+ */
+
+package tech.libeufin.common.crypto
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider
+import java.io.ByteArrayOutputStream
+import java.io.InputStream
+import java.math.BigInteger
+import java.security.*
+import java.security.interfaces.RSAPrivateCrtKey
+import java.security.interfaces.RSAPublicKey
+import java.security.spec.*
+import javax.crypto.*
+import javax.crypto.spec.IvParameterSpec
+import javax.crypto.spec.PBEKeySpec
+import javax.crypto.spec.PBEParameterSpec
+import javax.crypto.spec.SecretKeySpec
+import java.util.Base64
+import tech.libeufin.common.*
+
+/** Cryptographic operations for secure password storage and verification */
+object PwCrypto {
+ // TODO Use a real password hashing method to store passwords
+
+ private val SECURE_RNG = SecureRandom()
+
+ /** Hash [pw] using the strongest supported hashing method */
+ fun hashpw(pw: String): String {
+ val saltBytes = ByteArray(8)
+ SECURE_RNG.nextBytes(saltBytes)
+ val salt = saltBytes.encodeBase64()
+ val pwh = CryptoUtil.hashStringSHA256("$salt|$pw").encodeBase64()
+ return "sha256-salted\$$salt\$$pwh"
+ }
+
+ /** Check whether [pw] match hashed [storedPwHash] */
+ fun checkpw(pw: String, storedPwHash: String): Boolean {
+ val components = storedPwHash.split('$')
+ when (val algo = components[0]) {
+ "sha256" -> { // Support legacy unsalted passwords
+ if (components.size != 2) throw Exception("bad password hash")
+ val hash = components[1]
+ val pwh = CryptoUtil.hashStringSHA256(pw).encodeBase64()
+ return pwh == hash
+ }
+ "sha256-salted" -> {
+ if (components.size != 3) throw Exception("bad password hash")
+ val salt = components[1]
+ val hash = components[2]
+ val pwh = CryptoUtil.hashStringSHA256("$salt|$pw").encodeBase64()
+ return pwh == hash
+ }
+ else -> throw Exception("unsupported hash algo: '$algo'")
+ }
+ }
+}
diff --git a/common/src/main/kotlin/CryptoUtil.kt b/common/src/main/kotlin/crypto/utils.kt
index a4560c29..6bad9741 100644
--- a/common/src/main/kotlin/CryptoUtil.kt
+++ b/common/src/main/kotlin/crypto/utils.kt
@@ -17,7 +17,7 @@
* <http://www.gnu.org/licenses/>
*/
-package tech.libeufin.common
+package tech.libeufin.common.crypto
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.io.ByteArrayOutputStream
@@ -32,11 +32,13 @@ import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.PBEParameterSpec
import javax.crypto.spec.SecretKeySpec
+import tech.libeufin.common.*
/**
* Helpers for dealing with cryptographic operations in EBICS / LibEuFin.
*/
object CryptoUtil {
+ // TODO split common and ebics crypto
/**
* RSA key pair.
@@ -286,32 +288,4 @@ object CryptoUtil {
fun hashStringSHA256(input: String): ByteArray {
return MessageDigest.getInstance("SHA-256").digest(input.toByteArray(Charsets.UTF_8))
}
-
- fun hashpw(pw: String): String {
- val saltBytes = ByteArray(8)
- SecureRandom().nextBytes(saltBytes)
- val salt = bytesToBase64(saltBytes)
- val pwh = bytesToBase64(hashStringSHA256("$salt|$pw"))
- return "sha256-salted\$$salt\$$pwh"
- }
-
- fun checkpw(pw: String, storedPwHash: String): Boolean {
- val components = storedPwHash.split('$')
- when (val algo = components[0]) {
- "sha256" -> { // Support legacy unsalted passwords
- if (components.size != 2) throw Exception("bad password hash")
- val hash = components[1]
- val pwh = bytesToBase64(hashStringSHA256(pw))
- return pwh == hash
- }
- "sha256-salted" -> {
- if (components.size != 3) throw Exception("bad password hash")
- val salt = components[1]
- val hash = components[2]
- val pwh = bytesToBase64(hashStringSHA256("$salt|$pw"))
- return pwh == hash
- }
- else -> throw Exception("unsupported hash algo: '$algo'")
- }
- }
-}
+} \ No newline at end of file
diff --git a/common/src/main/kotlin/strings.kt b/common/src/main/kotlin/strings.kt
index b3608ec2..3fa5f564 100644
--- a/common/src/main/kotlin/strings.kt
+++ b/common/src/main/kotlin/strings.kt
@@ -52,12 +52,13 @@ fun decodeHexString(hexString: String): ByteArray {
return bytes
}
-fun bytesToBase64(bytes: ByteArray): String {
- return Base64.getEncoder().encodeToString(bytes)
+
+fun ByteArray.encodeBase64(): String {
+ return Base64.getEncoder().encodeToString(this)
}
-fun base64ToBytes(encoding: String): ByteArray {
- return Base64.getDecoder().decode(encoding)
+fun String.decodeBase64(): ByteArray {
+ return Base64.getDecoder().decode(this)
}
// used mostly in RSA math, never as amount.
diff --git a/common/src/test/kotlin/CryptoUtilTest.kt b/common/src/test/kotlin/CryptoUtilTest.kt
index a4778369..11d87055 100644
--- a/common/src/test/kotlin/CryptoUtilTest.kt
+++ b/common/src/test/kotlin/CryptoUtilTest.kt
@@ -21,6 +21,7 @@ import org.junit.Ignore
import org.junit.Test
import kotlin.io.path.*
import tech.libeufin.common.*
+import tech.libeufin.common.crypto.*
import java.security.KeyPairGenerator
import java.security.interfaces.RSAPrivateCrtKey
import java.util.*
@@ -202,7 +203,7 @@ class CryptoUtilTest {
@Test
fun passwordHashing() {
- val x = CryptoUtil.hashpw("myinsecurepw")
- assertTrue(CryptoUtil.checkpw("myinsecurepw", x))
+ val x = PwCrypto.hashpw("myinsecurepw")
+ assertTrue(PwCrypto.checkpw("myinsecurepw", x))
}
}
diff --git a/ebics/src/main/kotlin/Ebics.kt b/ebics/src/main/kotlin/Ebics.kt
index ab591b61..e335e502 100644
--- a/ebics/src/main/kotlin/Ebics.kt
+++ b/ebics/src/main/kotlin/Ebics.kt
@@ -26,7 +26,7 @@ package tech.libeufin.ebics
import io.ktor.http.*
import org.w3c.dom.Document
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.ebics.ebics_h004.EbicsRequest
import tech.libeufin.ebics.ebics_h004.EbicsResponse
import tech.libeufin.ebics.ebics_h004.EbicsTypes
diff --git a/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt b/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt
index 8282e8b4..7ca7c6b9 100644
--- a/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt
+++ b/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt
@@ -1,7 +1,7 @@
package tech.libeufin.ebics.ebics_h004
import org.apache.xml.security.binding.xmldsig.SignatureType
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import java.math.BigInteger
import java.security.interfaces.RSAPublicKey
import java.util.*
diff --git a/ebics/src/main/kotlin/ebics_h004/EbicsResponse.kt b/ebics/src/main/kotlin/ebics_h004/EbicsResponse.kt
index 709e4569..373bb8f3 100644
--- a/ebics/src/main/kotlin/ebics_h004/EbicsResponse.kt
+++ b/ebics/src/main/kotlin/ebics_h004/EbicsResponse.kt
@@ -1,7 +1,7 @@
package tech.libeufin.ebics.ebics_h004
import org.apache.xml.security.binding.xmldsig.SignatureType
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import java.math.BigInteger
import javax.xml.bind.annotation.*
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter
diff --git a/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt b/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt
index b6ca5df3..c8370d4c 100644
--- a/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt
+++ b/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt
@@ -1,7 +1,7 @@
package tech.libeufin.ebics.ebics_h005
import org.apache.xml.security.binding.xmldsig.SignatureType
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import java.math.BigInteger
import java.security.interfaces.RSAPublicKey
import java.util.*
diff --git a/ebics/src/main/kotlin/ebics_h005/Ebics3Response.kt b/ebics/src/main/kotlin/ebics_h005/Ebics3Response.kt
index d648f541..dd4b18a2 100644
--- a/ebics/src/main/kotlin/ebics_h005/Ebics3Response.kt
+++ b/ebics/src/main/kotlin/ebics_h005/Ebics3Response.kt
@@ -1,7 +1,7 @@
package tech.libeufin.ebics.ebics_h005
import org.apache.xml.security.binding.xmldsig.SignatureType
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.ebics.ebics_h004.EbicsTypes
import java.math.BigInteger
import javax.xml.bind.annotation.*
diff --git a/ebics/src/test/kotlin/EbicsMessagesTest.kt b/ebics/src/test/kotlin/EbicsMessagesTest.kt
index bf55b392..28820374 100644
--- a/ebics/src/test/kotlin/EbicsMessagesTest.kt
+++ b/ebics/src/test/kotlin/EbicsMessagesTest.kt
@@ -21,7 +21,7 @@ import junit.framework.TestCase.assertEquals
import org.apache.xml.security.binding.xmldsig.SignatureType
import org.junit.Test
import org.w3c.dom.Element
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.ebics.XMLUtil
import tech.libeufin.ebics.ebics_h004.*
import tech.libeufin.ebics.ebics_hev.HEVResponse
diff --git a/ebics/src/test/kotlin/SignatureDataTest.kt b/ebics/src/test/kotlin/SignatureDataTest.kt
index 435962c3..9c5e4da6 100644
--- a/ebics/src/test/kotlin/SignatureDataTest.kt
+++ b/ebics/src/test/kotlin/SignatureDataTest.kt
@@ -19,7 +19,7 @@
import org.apache.xml.security.binding.xmldsig.SignatureType
import org.junit.Test
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.ebics.XMLUtil
import tech.libeufin.ebics.ebics_h004.EbicsRequest
import tech.libeufin.ebics.ebics_h004.EbicsTypes
diff --git a/ebics/src/test/kotlin/XmlUtilTest.kt b/ebics/src/test/kotlin/XmlUtilTest.kt
index 078037d2..8b8f340f 100644
--- a/ebics/src/test/kotlin/XmlUtilTest.kt
+++ b/ebics/src/test/kotlin/XmlUtilTest.kt
@@ -20,7 +20,7 @@
import org.apache.xml.security.binding.xmldsig.SignatureType
import org.junit.Assert.assertTrue
import org.junit.Test
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.common.decodeBase64
import tech.libeufin.ebics.XMLUtil
import tech.libeufin.ebics.XMLUtil.Companion.signEbicsResponse
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt
index df2f8f15..685ad772 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt
@@ -25,6 +25,7 @@ import com.github.ajalt.clikt.parameters.options.*
import io.ktor.client.*
import kotlinx.coroutines.runBlocking
import tech.libeufin.common.*
+import tech.libeufin.common.crypto.*
import tech.libeufin.ebics.*
import tech.libeufin.nexus.ebics.*
import java.nio.file.*
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt
index cf981a60..fd91cfd4 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/KeyFiles.kt
@@ -31,7 +31,7 @@ import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import tech.libeufin.common.Base32Crockford
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import java.nio.file.*
import java.security.interfaces.RSAPrivateCrtKey
import java.security.interfaces.RSAPublicKey
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt
index 7eebcea8..929246af 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt
@@ -44,6 +44,7 @@ import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.utils.io.jvm.javaio.*
import tech.libeufin.common.*
+import tech.libeufin.common.crypto.*
import tech.libeufin.ebics.*
import tech.libeufin.ebics.ebics_h005.Ebics3Request
import tech.libeufin.nexus.*
diff --git a/nexus/src/test/kotlin/CliTest.kt b/nexus/src/test/kotlin/CliTest.kt
index 6776e7f2..7e03053d 100644
--- a/nexus/src/test/kotlin/CliTest.kt
+++ b/nexus/src/test/kotlin/CliTest.kt
@@ -19,7 +19,7 @@
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.testing.test
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.nexus.*
import java.io.ByteArrayOutputStream
import java.io.PrintStream
diff --git a/nexus/src/test/kotlin/Keys.kt b/nexus/src/test/kotlin/Keys.kt
index 765afcc1..826ec77e 100644
--- a/nexus/src/test/kotlin/Keys.kt
+++ b/nexus/src/test/kotlin/Keys.kt
@@ -18,7 +18,7 @@
*/
import org.junit.Test
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.nexus.*
import kotlin.io.path.Path
import kotlin.io.path.deleteIfExists
diff --git a/nexus/src/test/kotlin/MySerializers.kt b/nexus/src/test/kotlin/MySerializers.kt
index 3aa2c803..98707948 100644
--- a/nexus/src/test/kotlin/MySerializers.kt
+++ b/nexus/src/test/kotlin/MySerializers.kt
@@ -19,7 +19,7 @@
import org.junit.Test
import tech.libeufin.common.Base32Crockford
-import tech.libeufin.common.CryptoUtil
+import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.nexus.ClientPrivateKeysFile
import tech.libeufin.nexus.JSON
import kotlin.test.assertEquals