Skip to content

Commit 3e2261e

Browse files
Refactor CryptoUtils class
This commit re-organizes and renames methods for better use
1 parent 8061f88 commit 3e2261e

15 files changed

+130
-137
lines changed

node/src/main/scala/io/iohk/atala/prism/node/auth/AuthenticatorF.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import io.iohk.atala.prism.node.auth.errors._
1212
import io.iohk.atala.prism.node.identity.{PrismDid => DID}
1313
import io.iohk.atala.prism.node.auth.grpc.GrpcAuthenticationHeader
1414
import io.iohk.atala.prism.node.auth.utils.DIDUtils
15-
import io.iohk.atala.prism.node.crypto.CryptoUtils.{SecpECDSASignature, SecpPublicKey}
15+
import io.iohk.atala.prism.node.crypto.CryptoUtils.{SecpECDSA, SecpECDSASignature, SecpPublicKey}
1616
import io.iohk.atala.prism.protos.node_api
1717
import scalapb.GeneratedMessage
1818
import tofu.Execute
@@ -141,7 +141,7 @@ private[auth] class WhitelistedAuthenticatorFImpl[F[_]: Monad](burnAuth: Whiteli
141141
signature: SecpECDSASignature
142142
): F[Either[AuthError, Unit]] = {
143143
val payload = requestNonce.mergeWith(request).toArray
144-
val isVerified = Try(SecpPublicKey.checkECDSASignature(payload, signature.bytes, publicKey)).getOrElse(false)
144+
val isVerified = Try(SecpECDSA.checkECDSASignature(payload, signature.bytes, publicKey)).getOrElse(false)
145145
Applicative[F].pure(
146146
Either
147147
.cond[AuthError, Unit](

node/src/main/scala/io/iohk/atala/prism/node/auth/grpc/GrpcAuthenticationContext.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private[grpc] object GrpcAuthenticationContext {
131131
ctx.getOpt(PublicKeyKeys)
132132
) match {
133133
case (Some(requestNonce), Some(signature), Some(encodedPublicKey)) =>
134-
val publicKey = SecpPublicKey.unsafetoPublicKeyFromUncompressed(encodedPublicKey)
134+
val publicKey = SecpPublicKey.unsafeFromUncompressed(encodedPublicKey)
135135
val header = GrpcAuthenticationHeader.PublicKeyBased(
136136
requestNonce = RequestNonce(requestNonce.toVector),
137137
publicKey = publicKey,

node/src/main/scala/io/iohk/atala/prism/node/auth/utils/DIDUtils.scala

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package io.iohk.atala.prism.node.auth.utils
22

33
import io.iohk.atala.prism.node.auth.errors._
44
import io.iohk.atala.prism.node.identity.{LongFormPrismDid, PrismDid => DID}
5-
import io.iohk.atala.prism.node.crypto.CryptoUtils
65
import io.iohk.atala.prism.node.crypto.CryptoUtils.SecpPublicKey
76
import io.iohk.atala.prism.node.utils.FutureEither
87
import io.iohk.atala.prism.protos.node_models.AtalaOperation.Operation.CreateDid
@@ -55,7 +54,7 @@ object DIDUtils {
5554
publicKey: SecpPublicKey
5655
): Option[SecpPublicKey] =
5756
Option.when(
58-
publicKey.curveName == curve && CryptoUtils.isSecp256k1(publicKey)
57+
publicKey.curveName == curve && SecpPublicKey.isSecp256k1(publicKey)
5958
)(publicKey)
6059

6160
def findPublicKey(didData: node_models.DIDData, keyId: String)(implicit
@@ -73,20 +72,20 @@ object DIDUtils {
7372
if (data.x.size() > 32)
7473
verifyPublicKey(
7574
data.curve,
76-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(data.x.toByteArray.toVector)
75+
SecpPublicKey.unsafeFromCompressed(data.x.toByteArray.toVector)
7776
)
7877
else
7978
verifyPublicKey(
8079
data.curve,
81-
SecpPublicKey.unsafeToSecpPublicKeyFromByteCoordinates(
80+
SecpPublicKey.unsafeFromByteCoordinates(
8281
data.x.toByteArray,
8382
data.y.toByteArray
8483
)
8584
)
8685
case CompressedEcKeyData(data) =>
8786
verifyPublicKey(
8887
data.curve,
89-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(data.data.toByteArray.toVector)
88+
SecpPublicKey.unsafeFromCompressed(data.data.toByteArray.toVector)
9089
)
9190
case Empty => None
9291
}
@@ -108,20 +107,20 @@ object DIDUtils {
108107
if (data.x.size() > 32)
109108
verifyPublicKey(
110109
data.curve,
111-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(data.x.toByteArray.toVector)
110+
SecpPublicKey.unsafeFromCompressed(data.x.toByteArray.toVector)
112111
)
113112
else
114113
verifyPublicKey(
115114
data.curve,
116-
SecpPublicKey.unsafeToSecpPublicKeyFromByteCoordinates(
115+
SecpPublicKey.unsafeFromByteCoordinates(
117116
data.x.toByteArray,
118117
data.y.toByteArray
119118
)
120119
)
121120
case CompressedEcKeyData(data) =>
122121
verifyPublicKey(
123122
data.curve,
124-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(data.data.toByteArray.toVector)
123+
SecpPublicKey.unsafeFromCompressed(data.data.toByteArray.toVector)
125124
)
126125
case Empty => None
127126
}

node/src/main/scala/io/iohk/atala/prism/node/crypto/CryptoUtils.scala

Lines changed: 91 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,15 @@ import scala.util.Try
1515

1616
object CryptoUtils {
1717

18+
private val provider = new BouncyCastleProvider()
19+
Security.addProvider(provider)
20+
1821
implicit class SecpPublicKeyOps(pubKey: SecpPublicKey) {
1922
def toProto: CompressedECKeyData =
2023
CompressedECKeyData(curve = ProtocolConstants.secpCurveName, data = ByteString.copyFrom(pubKey.compressed))
2124
}
2225

23-
def isSecp256k1(key: SecpPublicKey): Boolean = {
24-
val params = ECNamedCurveTable.getParameterSpec("secp256k1")
25-
val curve = params.getCurve
26-
val x = new BigInteger(1, key.x)
27-
val y = new BigInteger(1, key.y)
28-
Try(curve.validatePoint(x, y)).isSuccess
29-
30-
}
31-
32-
trait SecpPublicKey {
26+
sealed trait SecpPublicKey {
3327
private[crypto] def publicKey: PublicKey
3428
def curveName: String = ProtocolConstants.secpCurveName
3529
def compressed: Array[Byte] = publicKey
@@ -47,73 +41,11 @@ object CryptoUtils {
4741
override private[crypto] def publicKey: PublicKey = pubKey
4842
}
4943

50-
trait SecpECDSASignature {
51-
def bytes: Array[Byte]
52-
}
53-
private[crypto] case class SecpECDSASignatureImpl(bytes: Array[Byte]) extends SecpECDSASignature
54-
55-
object SecpECDSASignature {
56-
def fromBytes(bytes: Array[Byte]): SecpECDSASignature = SecpECDSASignatureImpl(bytes)
57-
}
58-
59-
object SecpPrivateKey {
60-
def unsafefromBytesCompressed(bytes: Array[Byte]): SecpPrivateKey = SecpPrivateKeyImpl(bytes)
61-
}
62-
63-
trait SecpPrivateKey {
64-
private[crypto] def bytes: Array[Byte]
65-
private[crypto] def privateKey: PrivateKey
66-
def getEncoded: Array[Byte]
67-
}
68-
private[crypto] case class SecpPrivateKeyImpl(bytes: Array[Byte]) extends SecpPrivateKey {
69-
override def getEncoded: Array[Byte] = {
70-
privateKey
71-
.asInstanceOf[ECPrivateKey]
72-
.getD
73-
.toByteArray
74-
.dropWhile(_ == 0)
75-
}
76-
77-
override def privateKey: PrivateKey = {
78-
val ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1")
79-
val ecNamedCurveSpec: ECParameterSpec = new ECNamedCurveSpec(
80-
ecParameterSpec.getName,
81-
ecParameterSpec.getCurve,
82-
ecParameterSpec.getG,
83-
ecParameterSpec.getN
84-
)
85-
val bigInt = new BigInteger(1, bytes)
86-
val spec = new ECPrivateKeySpec(bigInt, ecNamedCurveSpec)
87-
val keyFactory = KeyFactory.getInstance("EC", provider)
88-
keyFactory.generatePrivate(spec)
89-
}
90-
}
91-
92-
object SecpECDSA {
93-
def signBytes(msg: Array[Byte], privateKey: SecpPrivateKey): SecpECDSASignature = {
94-
val signer = Signature.getInstance("SHA256withECDSA", provider)
95-
signer.initSign(privateKey.privateKey)
96-
signer.update(msg)
97-
SecpECDSASignatureImpl(signer.sign())
98-
}
99-
}
100-
101-
// We define the constructor to SecpKeys private so that the only way to generate
102-
// these keys is by using the methods unsafeToPublicKeyFromByteCoordinates and
103-
// unsafeToPublicKeyFromCompressed.
10444
object SecpPublicKey {
10545

10646
private[crypto] def fromPublicKey(key: PublicKey): SecpPublicKey = new SecpPublicKeyImpl(key)
10747

108-
// move to SecpECDSA object
109-
def checkECDSASignature(msg: Array[Byte], sig: Array[Byte], pubKey: SecpPublicKey): Boolean = {
110-
val ecdsaVerify = Signature.getInstance("SHA256withECDSA", provider)
111-
ecdsaVerify.initVerify(pubKey.publicKey)
112-
ecdsaVerify.update(msg)
113-
ecdsaVerify.verify(sig)
114-
}
115-
116-
def unsafeToSecpPublicKeyFromCompressed(com: Vector[Byte]): SecpPublicKey = {
48+
def unsafeFromCompressed(com: Vector[Byte]): SecpPublicKey = {
11749
val params = ECNamedCurveTable.getParameterSpec("secp256k1")
11850
val fact = KeyFactory.getInstance("ECDSA", provider)
11951
val curve = params.getCurve
@@ -124,12 +56,13 @@ object CryptoUtils {
12456
SecpPublicKey.fromPublicKey(fact.generatePublic(keySpec))
12557
}
12658

127-
def unsafeToSecpPublicKeyFromByteCoordinates(x: Array[Byte], y: Array[Byte]): SecpPublicKey = {
59+
def unsafeFromByteCoordinates(x: Array[Byte], y: Array[Byte]): SecpPublicKey = {
60+
val PUBLIC_KEY_COORDINATE_BYTE_SIZE: Int = 32
12861
def trimLeadingZeroes(arr: Array[Byte], c: String): Array[Byte] = {
12962
val trimmed = arr.dropWhile(_ == 0.toByte)
13063
require(
13164
trimmed.length <= PUBLIC_KEY_COORDINATE_BYTE_SIZE,
132-
s"Expected $c coordinate byte length to be less than or equal ${PUBLIC_KEY_COORDINATE_BYTE_SIZE}, but got ${trimmed.length} bytes"
65+
s"Expected $c coordinate byte length to be less than or equal $PUBLIC_KEY_COORDINATE_BYTE_SIZE, but got ${trimmed.length} bytes"
13366
)
13467
trimmed
13568
}
@@ -138,10 +71,10 @@ object CryptoUtils {
13871
val yTrimmed = trimLeadingZeroes(y, "y")
13972
val xInteger = BigInt(1, xTrimmed)
14073
val yInteger = BigInt(1, yTrimmed)
141-
SecpPublicKey.unsafeToSecpPublicKeyFromBigIntegerCoordinates(xInteger, yInteger)
74+
SecpPublicKey.unsafeFromBigIntegerCoordinates(xInteger, yInteger)
14275
}
14376

144-
def unsafeToSecpPublicKeyFromBigIntegerCoordinates(x: BigInt, y: BigInt): SecpPublicKey = {
77+
private def unsafeFromBigIntegerCoordinates(x: BigInt, y: BigInt): SecpPublicKey = {
14578
val params = ECNamedCurveTable.getParameterSpec("secp256k1")
14679
val fact = KeyFactory.getInstance("ECDSA", provider)
14780
val curve = params.getCurve
@@ -152,7 +85,7 @@ object CryptoUtils {
15285
SecpPublicKey.fromPublicKey(fact.generatePublic(keySpec))
15386
}
15487

155-
def unsafetoPublicKeyFromUncompressed(bytes: Array[Byte]): SecpPublicKey = {
88+
def unsafeFromUncompressed(bytes: Array[Byte]): SecpPublicKey = {
15689
val PRIVATE_KEY_BYTE_SIZE: Int = 32
15790
val pointSize = PRIVATE_KEY_BYTE_SIZE * 2 + 1
15891
require(bytes.length == pointSize, s"Invalid public key bytes length, ${bytes.length}")
@@ -165,18 +98,83 @@ object CryptoUtils {
16598

16699
val x = new BigInteger(1, xBytes)
167100
val y = new BigInteger(1, yBytes)
168-
unsafeToSecpPublicKeyFromBigIntegerCoordinates(x, y)
101+
unsafeFromBigIntegerCoordinates(x, y)
102+
}
103+
104+
def isSecp256k1(key: SecpPublicKey): Boolean = {
105+
val params = ECNamedCurveTable.getParameterSpec("secp256k1")
106+
val curve = params.getCurve
107+
val x = new BigInteger(1, key.x)
108+
val y = new BigInteger(1, key.y)
109+
Try(curve.validatePoint(x, y)).isSuccess
169110
}
170111
}
171112

172-
private val provider = new BouncyCastleProvider()
173-
private val PUBLIC_KEY_COORDINATE_BYTE_SIZE: Int = 32
113+
sealed trait SecpECDSASignature {
114+
def bytes: Array[Byte]
115+
}
174116

175-
Security.addProvider(provider)
117+
private[crypto] case class SecpECDSASignatureImpl(bytes: Array[Byte]) extends SecpECDSASignature
118+
119+
object SecpECDSASignature {
120+
def fromBytes(bytes: Array[Byte]): SecpECDSASignature = SecpECDSASignatureImpl(bytes)
121+
}
122+
123+
sealed trait SecpPrivateKey {
124+
private[crypto] def bytes: Array[Byte]
125+
private[crypto] def privateKey: PrivateKey
126+
def getEncoded: Array[Byte]
127+
}
128+
129+
private[crypto] case class SecpPrivateKeyImpl(bytes: Array[Byte]) extends SecpPrivateKey {
130+
override def getEncoded: Array[Byte] = {
131+
privateKey
132+
.asInstanceOf[ECPrivateKey]
133+
.getD
134+
.toByteArray
135+
.dropWhile(_ == 0)
136+
}
176137

177-
trait Sha256Hash {
138+
override def privateKey: PrivateKey = {
139+
val ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1")
140+
val ecNamedCurveSpec: ECParameterSpec = new ECNamedCurveSpec(
141+
ecParameterSpec.getName,
142+
ecParameterSpec.getCurve,
143+
ecParameterSpec.getG,
144+
ecParameterSpec.getN
145+
)
146+
val bigInt = new BigInteger(1, bytes)
147+
val spec = new ECPrivateKeySpec(bigInt, ecNamedCurveSpec)
148+
val keyFactory = KeyFactory.getInstance("EC", provider)
149+
keyFactory.generatePrivate(spec)
150+
}
151+
}
152+
153+
object SecpPrivateKey {
154+
def unsafeFromBytesCompressed(bytes: Array[Byte]): SecpPrivateKey = SecpPrivateKeyImpl(bytes)
155+
}
156+
157+
object SecpECDSA {
158+
def signBytes(msg: Array[Byte], privateKey: SecpPrivateKey): SecpECDSASignature = {
159+
val signer = Signature.getInstance("SHA256withECDSA", provider)
160+
signer.initSign(privateKey.privateKey)
161+
signer.update(msg)
162+
SecpECDSASignatureImpl(signer.sign())
163+
}
164+
165+
def checkECDSASignature(msg: Array[Byte], sig: Array[Byte], pubKey: SecpPublicKey): Boolean = {
166+
val ecdsaVerify = Signature.getInstance("SHA256withECDSA", provider)
167+
ecdsaVerify.initVerify(pubKey.publicKey)
168+
ecdsaVerify.update(msg)
169+
ecdsaVerify.verify(sig)
170+
}
171+
}
172+
173+
sealed trait Sha256Hash {
178174
def bytes: Vector[Byte]
179-
def hexEncoded: String = bytesToHex(bytes)
175+
def hexEncoded: String = {
176+
bytes.map(byte => f"${byte & 0xff}%02x").mkString
177+
}
180178

181179
override def equals(obj: Any): Boolean = obj match {
182180
case other: Sha256Hash => bytes == other.bytes
@@ -211,19 +209,15 @@ object CryptoUtils {
211209
"The given hex string doesn't correspond to a valid SHA-256 hash encoded as string"
212210
)
213211
}
214-
}
215212

216-
def bytesToHex(bytes: Vector[Byte]): String = {
217-
bytes.map(byte => f"${byte & 0xff}%02x").mkString
218-
}
219-
220-
def hexToBytes(hex: String): Vector[Byte] = {
221-
val HEX_ARRAY = "0123456789abcdef".toCharArray
222-
for {
223-
pair <- hex.grouped(2).toVector
224-
firstIndex = HEX_ARRAY.indexOf(pair(0))
225-
secondIndex = HEX_ARRAY.indexOf(pair(1))
226-
octet = firstIndex << 4 | secondIndex
227-
} yield octet.toByte
213+
private def hexToBytes(hex: String): Vector[Byte] = {
214+
val HEX_ARRAY = "0123456789abcdef".toCharArray
215+
for {
216+
pair <- hex.grouped(2).toVector
217+
firstIndex = HEX_ARRAY.indexOf(pair(0))
218+
secondIndex = HEX_ARRAY.indexOf(pair(1))
219+
octet = firstIndex << 4 | secondIndex
220+
} yield octet.toByte
221+
}
228222
}
229223
}

node/src/main/scala/io/iohk/atala/prism/node/grpc/ProtoCodecs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ object ProtoCodecs {
134134
for {
135135
maybeX <- protoKey.keyData.ecKeyData
136136
maybeY <- protoKey.keyData.ecKeyData
137-
} yield SecpPublicKey.unsafeToSecpPublicKeyFromByteCoordinates(
137+
} yield SecpPublicKey.unsafeFromByteCoordinates(
138138
maybeX.x.toByteArray,
139139
maybeY.y.toByteArray
140140
)

node/src/main/scala/io/iohk/atala/prism/node/operations/CreateDIDOperation.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ case class CreateDIDOperation(
3939
}
4040
secpKey <- EitherT.fromEither[ConnectionIO] {
4141
val tryKey = Try {
42-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(key.key.compressedKey)
42+
SecpPublicKey.unsafeFromCompressed(key.key.compressedKey)
4343
}
4444
tryKey.toOption
4545
.toRight(IllegalSecp256k1Key(key.keyId))

node/src/main/scala/io/iohk/atala/prism/node/operations/DeactivateDIDOperation.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ case class DeactivateDIDOperation(
5858
}.map(_.key)
5959
secpKey <- EitherT.fromEither[ConnectionIO] {
6060
val tryKey = Try {
61-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(keyData.compressedKey)
61+
SecpPublicKey.unsafeFromCompressed(keyData.compressedKey)
6262
}
6363
tryKey.toOption
6464
.toRight(IllegalSecp256k1Key(keyId): StateError)

node/src/main/scala/io/iohk/atala/prism/node/operations/ParsingUtils.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ object ParsingUtils {
4646
Left(ecData.child(_.curve, "y").missing())
4747
} else {
4848
Try {
49-
val key = SecpPublicKey.unsafeToSecpPublicKeyFromByteCoordinates(
49+
val key = SecpPublicKey.unsafeFromByteCoordinates(
5050
ecData(_.x.toByteArray),
5151
ecData(_.y.toByteArray)
5252
)

node/src/main/scala/io/iohk/atala/prism/node/operations/ProtocolVersionUpdateOperation.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ case class ProtocolVersionUpdateOperation(
3939

4040
secpKey <- EitherT.fromEither[ConnectionIO] {
4141
val tryKey = Try {
42-
SecpPublicKey.unsafeToSecpPublicKeyFromCompressed(keyState.key.compressedKey)
42+
SecpPublicKey.unsafeFromCompressed(keyState.key.compressedKey)
4343
}
4444
tryKey.toOption
4545
.toRight(IllegalSecp256k1Key(keyId))

0 commit comments

Comments
 (0)