From 3051f8fa78a5ae328aea8286cc085887024c9c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ka=C4=9Fan=20Can=20=C5=9Eit?= Date: Sat, 25 Nov 2023 21:39:41 +0300 Subject: [PATCH] fix(weaver): usage of weak PRNG issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Logic Behind the Problem When RNG (Random Number Generator) values are not received through a hardware TRNG, seed values apply a certain pattern. (It takes a seed value such as a mathematical formula or time.) In response to this situation, there are various secure random classes to increase security. Solution Changes have been made to get random values using safe randomness instead of mathematical randomness. This increases the complexity of the pattern, making it difficult to discover even if data is listened to for long periods of time. The changes that have been made; - In the certificate_utils.go file, the random value was taken from the math class (mrand math/rand) and used. By taking this random value from the secure random class, we obtain a more reliable random value. I added HmacGenerate and generateSecureRandomKey functions for readability and ease of use. If you want to generate a key again, the generateSecureRandomKey function, which uses secure random, can be used. - In HashFunctions.kt, kotlin.random.Random class has been replaced with the more reliable java.security.SecureRandom class. - The reason for the change in eciesCrypto.js is that the length of aes-128-ctr is not considered reliable by various standards. For this reason, I preferred the more reliable 256 length. Fixes #2765 Signed-off-by: Kağan Can Şit --- .../contracts/interop/certificate_utils.go | 40 ++++++++++++++----- .../cacti/weaver/sdk/corda/HashFunctions.kt | 7 ++-- .../src/eciesCrypto.js | 2 +- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/weaver/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go b/weaver/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go index 71d233ba4f..af9f8d3f31 100644 --- a/weaver/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go +++ b/weaver/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go @@ -21,7 +21,6 @@ import ( "fmt" "hash" "math/big" - mrand "math/rand" "time" "golang.org/x/crypto/ed25519" @@ -207,7 +206,7 @@ func ecdsaVerify(verKey *ecdsa.PublicKey, msgHash, signature []byte) error { return nil } -//Validate Ed25519 signature +// Validate Ed25519 signature func verifyEd25519Signature(pubKey []byte, hashedMessage []byte, signature []byte) error { result := ed25519.Verify(pubKey, hashedMessage, signature) @@ -297,12 +296,31 @@ func encryptWithEd25519PublicKey(message []byte, pubKey []byte) ([]byte, error) return []byte(""), nil } +func generateSecureRandomKey(length int) ([]byte, error) { + key := make([]byte, length) + _, err := rand.Read(key) + if err != nil { + return nil, err + } + return key, nil +} + +func generateHMAC(data, key []byte) ([]byte, error) { + hmacHash := hmac.New(sha256.New, key) + _, err := hmacHash.Write(data) + if err != nil { + return nil, err + } + return hmacHash.Sum(nil), nil +} + func generateConfidentialInteropPayloadAndHash(message []byte, cert string) ([]byte, error) { // Generate a 16-byte random key for the HMAC - hashKey := make([]byte, 16) - for i := 0; i < 16 ; i++ { - hashKey[i] = byte(mrand.Intn(255)) + hashKey, err := generateSecureRandomKey(16) + if err != nil { + return []byte(""), err } + confidentialPayloadContents := common.ConfidentialPayloadContents{ Payload: message, Random: hashKey, @@ -311,22 +329,26 @@ func generateConfidentialInteropPayloadAndHash(message []byte, cert string) ([]b if err != nil { return []byte(""), err } + x509Cert, err := parseCert(cert) if err != nil { return []byte(""), err } + encryptedPayload, err := encryptWithCert(confidentialPayloadContentsBytes, x509Cert) if err != nil { return []byte(""), err } - payloadHMAC := hmac.New(sha256.New, hashKey) - payloadHMAC.Write(message) - payloadHMACBytes := payloadHMAC.Sum(nil) + payloadHMAC, err := generateHMAC(message, hashKey) + if err != nil { + return []byte(""), err + } + confidentialPayload := common.ConfidentialPayload{ EncryptedPayload: encryptedPayload, HashType: common.ConfidentialPayload_HMAC, - Hash: payloadHMACBytes, + Hash: payloadHMAC, } confidentialPayloadBytes, err := proto.Marshal(&confidentialPayload) if err != nil { diff --git a/weaver/sdks/corda/src/main/kotlin/org/hyperledger/cacti/weaver/sdk/corda/HashFunctions.kt b/weaver/sdks/corda/src/main/kotlin/org/hyperledger/cacti/weaver/sdk/corda/HashFunctions.kt index fac95b4436..3a5e247823 100644 --- a/weaver/sdks/corda/src/main/kotlin/org/hyperledger/cacti/weaver/sdk/corda/HashFunctions.kt +++ b/weaver/sdks/corda/src/main/kotlin/org/hyperledger/cacti/weaver/sdk/corda/HashFunctions.kt @@ -9,7 +9,7 @@ package org.hyperledger.cacti.weaver.sdk.corda; import java.util.Base64 import net.corda.core.utilities.OpaqueBytes import net.corda.core.crypto.sha256 -import kotlin.random.Random +import java.security.SecureRandom import org.hyperledger.cacti.weaver.protos.common.asset_locks.AssetLocks.HashMechanism import org.hyperledger.cacti.weaver.imodule.corda.states.sha512 @@ -42,8 +42,9 @@ class HashFunctions { override fun generateRandomPreimage(length: Int) { - val bytes = ByteArray(length) - Random.nextBytes(bytes) + val secureRandom = SecureRandom.getInstanceStrong(); + val bytes = ByteArray(length); + secureRandom.nextBytes(bytes); this.setPreimage(Base64.getEncoder().encodeToString(bytes)); } override fun setPreimage(preImage: String) { diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/eciesCrypto.js b/weaver/sdks/fabric/interoperation-node-sdk/src/eciesCrypto.js index 297e1e0496..70496955eb 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/src/eciesCrypto.js +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/eciesCrypto.js @@ -161,7 +161,7 @@ function eciesEncryptMessage(recipientPublicKey, msg, options) { const hKm = bitsToBytes(hmacKeyHash.finalize()); const iv = crypto.randomBytes(IVLength); - const cipher = crypto.createCipheriv("aes-128-ctr", Buffer.from(aesKey), iv); + const cipher = crypto.createCipheriv("aes-256-ctr", Buffer.from(aesKey), iv); const encryptedBytes = cipher.update(msg); const EM = Buffer.concat([iv, encryptedBytes]); const D = hmac(hKm, EM, options);