From cea95dd488c042ef199db3f82df716a97bc16e72 Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 13 Jan 2025 11:43:01 +0530 Subject: [PATCH 01/21] modify hash func in cryptoutils --- .../java/io/ballerina/stdlib/crypto/CryptoUtils.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java index f34e0249..37f5dc18 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java @@ -39,6 +39,9 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; +import org.bouncycastle.jcajce.provider.digest.Keccak; // import lib + + import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -124,7 +127,14 @@ public static Object hmac(String algorithm, byte[] key, byte[] input) { */ public static byte[] hash(String algorithm, byte[] input, Object salt) { try { - MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + MessageDigest messageDigest; + + if ("Keccak-256".equalsIgnoreCase(algorithm)) { + messageDigest = new Keccak.Digest256(); + } else { + messageDigest = MessageDigest.getInstance(algorithm); + } + if (salt != null) { messageDigest.update(((BArray) salt).getBytes()); } From 650fa7b5d9d28051167b1e94367c98ff1212d45a Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 13 Jan 2025 11:49:51 +0530 Subject: [PATCH 02/21] fix import order --- .../src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java index 37f5dc18..8cd3adc1 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java @@ -34,14 +34,12 @@ import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jcajce.provider.digest.Keccak; import org.bouncycastle.jcajce.spec.KEMExtractSpec; import org.bouncycastle.jcajce.spec.KEMGenerateSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; -import org.bouncycastle.jcajce.provider.digest.Keccak; // import lib - - import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; From 9a512a0908e45c1a46fc9aaa3b68d6edaf858466 Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 13 Jan 2025 12:12:56 +0530 Subject: [PATCH 03/21] edit hash.bal --- ballerina/hash.bal | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ballerina/hash.bal b/ballerina/hash.bal index 18eecf6e..5e21f51f 100644 --- a/ballerina/hash.bal +++ b/ballerina/hash.bal @@ -104,3 +104,18 @@ public isolated function crc32b(byte[] input) returns string = @java:Method { name: "crc32b", 'class: "io.ballerina.stdlib.crypto.nativeimpl.Hash" } external; + +# Returns the Keccak-256 hash of the given data. +# ```ballerina +# string dataString = "Hello Ballerina"; +# byte[] data = dataString.toBytes(); +# byte[] hash = crypto:hashKeccak256(data); +# ``` +# +# + input - Value to be hashed +# + salt - Salt to be added +# + return - Hashed output +public isolated function hashKeccak256(byte[] input, byte[]? salt = ()) returns byte[] = @java:Method { + name: "hashKeccak256", + 'class: "io.ballerina.stdlib.crypto.nativeimpl.Hash" +} external; From afa58ceca2c8fe9091f58faaa45e905ab0be5484 Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 13 Jan 2025 13:38:02 +0530 Subject: [PATCH 04/21] edit Hash.java --- .../main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java index c4c04e59..c4f52bcb 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java @@ -64,4 +64,8 @@ public static BArray hashSha512(BArray inputValue, Object saltValue) { return ValueCreator.createArrayValue(CryptoUtils.hash("SHA-512", inputValue.getBytes(), saltValue)); } + public static BArray hashKeccak256(BArray inputValue, Object saltValue) { + return ValueCreator.createArrayValue(CryptoUtils.hash("Keccak-256", inputValue.getBytes(), saltValue)); + } + } From afe1a51e11ecb5f43e86ce71181616a6569b4a52 Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 13 Jan 2025 13:49:38 +0530 Subject: [PATCH 05/21] add tests --- ballerina/tests/hash_test.bal | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ballerina/tests/hash_test.bal b/ballerina/tests/hash_test.bal index a8c58982..9c9a2bfa 100644 --- a/ballerina/tests/hash_test.bal +++ b/ballerina/tests/hash_test.bal @@ -102,3 +102,11 @@ isolated function testHashSha512WithSalt() { "5E78702995D181042420860B111781AFEE88ACD455CAA0367271C78DAE0F69DA").toLowerAscii(); test:assertEquals(hashSha512(input, salt).toBase16(), expectedSha512Hash); } + +@test:Config {} +isolated function testHashKeccak256() { + byte[] input = "Ballerina test".toBytes(); + string expectedKeccak256Hash = + "73b6cc25ab0656625ee654a6cdc8f1d1803a6330fba4f4bf5bd6b9018f7d3131".toLowerAscii(); + test:assertEquals(hashKeccak256(input).toBase16(), expectedKeccak256Hash); +} From bc9db4ec1b4d36f9c708d2a00c0136b03b6f7317 Mon Sep 17 00:00:00 2001 From: Thilan Date: Tue, 14 Jan 2025 06:26:09 +0530 Subject: [PATCH 06/21] update readme file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ab9206f..766cebd1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Ballerina `crypto` library facilitates APIs to do operations like hashing, H ### Hashes -The `crypto` library supports generating hashes with 5 different hash algorithms MD5, SHA1, SHA256, SHA384, and SHA512. Also, it supports generating the CRC32B checksum. +The `crypto` library supports generating hashes with 6 different hash algorithms MD5, SHA1, SHA256, SHA384, SHA512, and Keccak 256. Also, it supports generating the CRC32B checksum. ### HMAC From 54124949acdd56ebfc104a7279503ad8fc661488 Mon Sep 17 00:00:00 2001 From: Thilan Date: Tue, 14 Jan 2025 06:30:27 +0530 Subject: [PATCH 07/21] update readme file --- README.md | 2 +- ballerina/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 766cebd1..04736c14 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Ballerina `crypto` library facilitates APIs to do operations like hashing, H ### Hashes -The `crypto` library supports generating hashes with 6 different hash algorithms MD5, SHA1, SHA256, SHA384, SHA512, and Keccak 256. Also, it supports generating the CRC32B checksum. +The `crypto` library supports generating hashes with 6 different hash algorithms MD5, SHA1, SHA256, SHA384, SHA512, and Keccak256. Also, it supports generating the CRC32B checksum. ### HMAC diff --git a/ballerina/README.md b/ballerina/README.md index 54195ce9..5f6ead22 100644 --- a/ballerina/README.md +++ b/ballerina/README.md @@ -6,7 +6,7 @@ The Ballerina `crypto` module facilitates APIs to do operations like hashing, HM ### Hashes -The `crypto` module supports generating hashes with 5 different hash algorithms MD5, SHA1, SHA256, SHA384, and SHA512. Also, it supports generating the CRC32B checksum. +The `crypto` library supports generating hashes with 6 different hash algorithms MD5, SHA1, SHA256, SHA384, SHA512, and Keccak256. Also, it supports generating the CRC32B checksum. ### HMAC From f5ab12def201704e1c9025b79cd8b08188eaf9a8 Mon Sep 17 00:00:00 2001 From: Thilan Date: Tue, 14 Jan 2025 06:39:03 +0530 Subject: [PATCH 08/21] fix typo in readme --- ballerina/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/README.md b/ballerina/README.md index 5f6ead22..e1ecd699 100644 --- a/ballerina/README.md +++ b/ballerina/README.md @@ -6,7 +6,7 @@ The Ballerina `crypto` module facilitates APIs to do operations like hashing, HM ### Hashes -The `crypto` library supports generating hashes with 6 different hash algorithms MD5, SHA1, SHA256, SHA384, SHA512, and Keccak256. Also, it supports generating the CRC32B checksum. +The `crypto` module supports generating hashes with 6 different hash algorithms MD5, SHA1, SHA256, SHA384, SHA512, and Keccak256. Also, it supports generating the CRC32B checksum. ### HMAC From 4c7c885182c8e5efab8ece5b708f6af9649f7fde Mon Sep 17 00:00:00 2001 From: Thilan Dissanayaka <43875064+thil4n@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:12:21 +0530 Subject: [PATCH 09/21] Update Hash.java --- .../main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java | 1 - 1 file changed, 1 deletion(-) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java index c4f52bcb..46495c44 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java @@ -67,5 +67,4 @@ public static BArray hashSha512(BArray inputValue, Object saltValue) { public static BArray hashKeccak256(BArray inputValue, Object saltValue) { return ValueCreator.createArrayValue(CryptoUtils.hash("Keccak-256", inputValue.getBytes(), saltValue)); } - } From 2f46e5357ae7b9f02e964aa1be2bd264726174ff Mon Sep 17 00:00:00 2001 From: Thilan Dissanayaka <43875064+thil4n@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:07:50 +0530 Subject: [PATCH 10/21] Update Hash.java --- .../io/ballerina/stdlib/crypto/nativeimpl/Hash.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java index 46495c44..6b453452 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java @@ -45,26 +45,26 @@ public static BString crc32b(BArray input) { } public static BArray hashMd5(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash("MD5", inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.MD5.getAlgorithmName(), inputValue.getBytes(), saltValue)); } public static BArray hashSha1(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash("SHA-1", inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA1.getAlgorithmName(), inputValue.getBytes(), saltValue)); } public static BArray hashSha256(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash("SHA-256", inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA256.getAlgorithmName(), inputValue.getBytes(), saltValue)); } public static BArray hashSha384(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash("SHA-384", inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA384.getAlgorithmName(), inputValue.getBytes(), saltValue)); } public static BArray hashSha512(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash("SHA-512", inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA512.getAlgorithmName(), inputValue.getBytes(), saltValue)); } public static BArray hashKeccak256(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash("Keccak-256", inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.KECCAK256.getAlgorithmName(), inputValue.getBytes(), saltValue)); } } From 76042652b5808c069f888e8d0c4b33ecc9011d98 Mon Sep 17 00:00:00 2001 From: Thilan Dissanayaka <43875064+thil4n@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:09:15 +0530 Subject: [PATCH 11/21] Create HashAlgorithm.java --- .../crypto/nativeimpl/HashAlgorithm.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java new file mode 100644 index 00000000..d5ae4144 --- /dev/null +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.stdlib.crypto.nativeimpl; + +/** + * Enum for supported hash algorithms. + */ +public enum HashAlgorithm { + MD5("MD5"), + SHA1("SHA-1"), + SHA256("SHA-256"), + SHA384("SHA-384"), + SHA512("SHA-512"), + KECCAK256("Keccak-256"); + + private final String algorithmName; + + HashAlgorithm(String algorithmName) { + this.algorithmName = algorithmName; + } + + public String getAlgorithmName() { + return algorithmName; + } +} From 1a62c7be6ac4734a4805ac4acbeb5a98576ce917 Mon Sep 17 00:00:00 2001 From: Thilan Date: Thu, 16 Jan 2025 21:12:51 +0530 Subject: [PATCH 12/21] add constants --- .../crypto-native/native-image.properties | 19 + .../crypto-native/reflect-config.json | 506 ++++++++++++++++++ .../io/ballerina/stdlib/crypto/Constants.java | 8 + 3 files changed, 533 insertions(+) create mode 100644 native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/native-image.properties create mode 100644 native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/reflect-config.json diff --git a/native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/native-image.properties b/native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/native-image.properties new file mode 100644 index 00000000..45f2f156 --- /dev/null +++ b/native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/native-image.properties @@ -0,0 +1,19 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you under the Apache License, +# Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +Args = --initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG\$Default \ + --initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG\$NonceAndIV \ + --features=io.ballerina.stdlib.crypto.svm.BouncyCastleFeature diff --git a/native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/reflect-config.json b/native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/reflect-config.json new file mode 100644 index 00000000..ddcafcaa --- /dev/null +++ b/native/bin/main/META-INF/native-image/io.ballerina.stdlib/crypto-native/reflect-config.json @@ -0,0 +1,506 @@ +[ + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.COMPOSITE$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.DSTU4145$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.Dilithium$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.ECGOST$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.EXTERNAL$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.EdEC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.ElGamal$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.Falcon$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.GM$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.GOST$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.IES$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.LMS$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.NTRU$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.RSA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.SPHINCSPlus$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.X509$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$ECDSA", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi$MD5", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi$SHA1", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi$SHA256", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi$SHA384", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi$SHA512", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Blake2b$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Blake2s$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Blake3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.DSTU7564$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.GOST3411$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Haraka$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Keccak$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.MD2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.MD4$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.MD5$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD160$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD256$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD320$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SHA1$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SHA224$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SHA256$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SHA3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SHA384$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SHA512$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.SM3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Skein$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Tiger$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.digest.Whirlpool$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.drbg.DRBG$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.keystore.BC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.keystore.BCFKS$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.AES$ECB", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.AES$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.ARC4$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.ARIA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Blowfish$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.CAST5$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.CAST6$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Camellia$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.ChaCha$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.DES$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$CBC", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$ECB", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$PBEWithSHAAndDES2Key", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.DSTU7624$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.GOST28147$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.GOST3412_2015$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Grain128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Grainv1$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.HC128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.HC256$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Noekeon$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.OpenSSLPBKDF$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.OpenSSLPBKDF$PBKDF", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF1$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2withUTF8", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Poly1305$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.RC5$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.RC6$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Rijndael$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.SCRYPT$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.SEED$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.SM4$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Salsa20$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Serpent$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Shacal2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Skipjack$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.TEA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.TLSKDF$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Threefish$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.VMPC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.VMPCKSA3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.XSalsa20$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.XTEA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.jcajce.provider.symmetric.Zuc$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.BIKE$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.CMCE$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.Dilithium$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.Falcon$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.Frodo$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.HQC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.Kyber$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.LMS$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.NH$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.NTRU$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.NTRUPrime$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.Picnic$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.Rainbow$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.SABER$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.SPHINCS$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.SPHINCSPlus$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.XMSS$Mappings", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.dilithium.DilithiumKeyFactorySpi$Base3", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.dilithium.SignatureSpi$Base3", + "methods":[{"name":"","parameterTypes":[] }] + }, + { + "name":"org.bouncycastle.pqc.jcajce.provider.kyber.KyberKeyFactorySpi$Kyber768", + "methods":[{"name":"","parameterTypes":[] }] + } +] diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/Constants.java b/native/src/main/java/io/ballerina/stdlib/crypto/Constants.java index faf301a5..ebb76a63 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/Constants.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/Constants.java @@ -135,4 +135,12 @@ private Constants() {} public static final String END_OF_INPUT_STREAM = "END_OF_INPUT_STREAM"; public static final String COMPRESSED_DATA_GENERATOR = "COMPRESSED_DATA_GENERATOR"; public static final String KEY_ENCRYPTED_DATA = "KEY_ENCRYPTED_DATA"; + + // Hashing Algorithms + public static final String MD5 = "MD5"; + public static final String SHA1 = "SHA-1"; + public static final String SHA256 = "SHA-256"; + public static final String SHA384 = "SHA-384"; + public static final String SHA512 = "SHA-512"; + public static final String KECCAK256 = "Keccak-256"; } From 1d3b63686ba9f7b9ef3a69c90f7ac273983f6ffe Mon Sep 17 00:00:00 2001 From: Thilan Date: Thu, 16 Jan 2025 21:14:30 +0530 Subject: [PATCH 13/21] replace enum with constants --- .../stdlib/crypto/nativeimpl/Hash.java | 13 +++--- .../crypto/nativeimpl/HashAlgorithm.java | 41 ------------------- 2 files changed, 7 insertions(+), 47 deletions(-) delete mode 100644 native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java index 6b453452..d3c99582 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Hash.java @@ -22,6 +22,7 @@ import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BString; +import io.ballerina.stdlib.crypto.Constants; import io.ballerina.stdlib.crypto.CryptoUtils; import java.util.zip.CRC32; @@ -45,26 +46,26 @@ public static BString crc32b(BArray input) { } public static BArray hashMd5(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.MD5.getAlgorithmName(), inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.MD5, inputValue.getBytes(), saltValue)); } public static BArray hashSha1(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA1.getAlgorithmName(), inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.SHA1, inputValue.getBytes(), saltValue)); } public static BArray hashSha256(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA256.getAlgorithmName(), inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.SHA256, inputValue.getBytes(), saltValue)); } public static BArray hashSha384(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA384.getAlgorithmName(), inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.SHA384, inputValue.getBytes(), saltValue)); } public static BArray hashSha512(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.SHA512.getAlgorithmName(), inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.SHA512, inputValue.getBytes(), saltValue)); } public static BArray hashKeccak256(BArray inputValue, Object saltValue) { - return ValueCreator.createArrayValue(CryptoUtils.hash(HashAlgorithm.KECCAK256.getAlgorithmName(), inputValue.getBytes(), saltValue)); + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.KECCAK256, inputValue.getBytes(), saltValue)); } } diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java deleted file mode 100644 index d5ae4144..00000000 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/HashAlgorithm.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.ballerina.stdlib.crypto.nativeimpl; - -/** - * Enum for supported hash algorithms. - */ -public enum HashAlgorithm { - MD5("MD5"), - SHA1("SHA-1"), - SHA256("SHA-256"), - SHA384("SHA-384"), - SHA512("SHA-512"), - KECCAK256("Keccak-256"); - - private final String algorithmName; - - HashAlgorithm(String algorithmName) { - this.algorithmName = algorithmName; - } - - public String getAlgorithmName() { - return algorithmName; - } -} From 8e249d848b2aaac1fa88d2f606fac2b0c31e7ef1 Mon Sep 17 00:00:00 2001 From: Thilan Date: Thu, 16 Jan 2025 21:16:21 +0530 Subject: [PATCH 14/21] Update CryptoUtils.java --- .../src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java index 8cd3adc1..5ad3306d 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java @@ -127,7 +127,7 @@ public static byte[] hash(String algorithm, byte[] input, Object salt) { try { MessageDigest messageDigest; - if ("Keccak-256".equalsIgnoreCase(algorithm)) { + if (Constants.KECCAK256.equals(algorithm)) { messageDigest = new Keccak.Digest256(); } else { messageDigest = MessageDigest.getInstance(algorithm); From 073870c881794a3c13a7790e1ab52e1b267d5706 Mon Sep 17 00:00:00 2001 From: Thilan Date: Thu, 16 Jan 2025 21:17:34 +0530 Subject: [PATCH 15/21] [Automated] Update the native jar versions --- ballerina/Dependencies.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index cc2aa1a7..748138aa 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,7 +5,7 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.11.0-20241121-075100-c4c87cbc" +distribution-version = "2201.11.0-20241218-101200-109f6cc7" [[package]] org = "ballerina" From 61774f7501cb22fadc5ccc506e9891576c49b1cd Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 20 Jan 2025 10:06:46 +0530 Subject: [PATCH 16/21] update spec.md --- docs/spec/spec.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/spec/spec.md b/docs/spec/spec.md index 40d51519..ba8c37c8 100644 --- a/docs/spec/spec.md +++ b/docs/spec/spec.md @@ -3,7 +3,7 @@ _Owners_: @shafreenAnfar @bhashinee _Reviewers_: @shafreenAnfar _Created_: 2022/08/23 -_Updated_: 2024/03/26 +_Updated_: 2025/01/20 _Edition_: Swan Lake ## Introduction @@ -25,6 +25,7 @@ The conforming implementation of the specification is released and included in t * 2.4. [SHA384](#24-sha384) * 2.5. [SHA512](#25-sha512) * 2.6. [CRC32B](#26-crc32b) + * 2.7. [KECCAK256](#27-keccak256) 3. [HMAC](#3-hmac) * 3.1. [MD5](#31-md5) * 3.2. [SHA1](#32-sha1) @@ -165,6 +166,15 @@ byte[] data = stringData.toBytes(); string checksum = crypto:crc32b(data); ``` +### 2.7. [KECCAK256](#27-keccak256) + +This API can be used to create the Hex-encoded KECCAK-256 value of the given data. +```ballerina +string stringData = "Hello Ballerina"; +byte[] data = stringData.toBytes(); +string checksum = crypto:hashKeccak256(data); +``` + ## 3. [HMAC](#3-hmac) The `crypto` library supports generating HMAC with 5 different hash algorithms: MD5, SHA1, SHA256, SHA384, and SHA512. From e9279ef2a6cebbcbd8ffeddd9e26365ae81a1aae Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 20 Jan 2025 12:02:05 +0530 Subject: [PATCH 17/21] update changelog.md --- changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index 1abac4da..82372701 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added +- [Introduce Keccak-256 hashing algorithm](https://github.com/ballerina-platform/ballerina-library/issues/7509) + +## [2.7.3] - 2025-01-20 + +### Added + - [Introduce new APIs to support PGP encryption and decryption with streams](https://github.com/ballerina-platform/ballerina-library/issues/7064) ## [2.7.2] - 2024-05-30 From 93aa1ec284d7166a3d219a844eba4a0d0be7a1f4 Mon Sep 17 00:00:00 2001 From: Thilan Date: Mon, 20 Jan 2025 13:02:48 +0530 Subject: [PATCH 18/21] add proposal --- docs/proposals/keccak-256-hashing-support.md | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/proposals/keccak-256-hashing-support.md diff --git a/docs/proposals/keccak-256-hashing-support.md b/docs/proposals/keccak-256-hashing-support.md new file mode 100644 index 00000000..08305d97 --- /dev/null +++ b/docs/proposals/keccak-256-hashing-support.md @@ -0,0 +1,37 @@ +# Proposal: Introduce support for keccak-256 hashing in the Ballerina Crypto Module + +_Authors_: @thil4n +_Reviewers_: +_Created_: 2024/05/29 +_Updated_: 2022/05/29 +_Issue_: [#7509](https://github.com/ballerina-platform/ballerina-library/issues/7509) + +## Summary + +This proposal introduces support for the keccak-256 hashing algorithm in the Ballerina Crypto Module. The keccak-256 algorithm is a cryptographic hash function and a critical component of many blockchain systems, including Ethereum. Adding keccak-256 will expand the cryptographic capabilities of the Ballerina Crypto Module. + +## Goals + +- Provide support for the keccak-256 hashing algorithm in the Ballerina Crypto Module. + +## Motivation + +The Ballerina Crypto Module currently supports several hashing algorithms, such as SHA-256, SHA-512, and others. However, keccak-256, a widely-used cryptographic hash function, is not yet supported. This function is essential for blockchain applications, as it is the primary hashing algorithm in Ethereum. + +The lack of native support for keccak-256 requires developers to rely on external libraries or workarounds, which adds complexity and reduces the seamless integration of blockchain-related functionality in Ballerina. Adding native support for keccak-256 will address this gap and enhance Ballerina's suitability for blockchain-related projects. + +## Description + +This proposal adds keccak-256 hashing to the Ballerina Crypto Module. + +The key functionalities expected from this change are as follows, + +- API to retrieve the hash of the input with `crypto:hashKeccak256`. + +### API additions + +A new API will be added to retrieve the hash of the input with `crypto:hashKeccak256` + +```ballerina +public isolated function hashKeccak256(byte[] input, byte[]? salt = ()) returns byte[]; +``` From 6ed5e68fa0318bb33f13f4f48144049c7e2b377e Mon Sep 17 00:00:00 2001 From: Thilan Date: Tue, 21 Jan 2025 09:52:17 +0530 Subject: [PATCH 19/21] update CryptoUtils.java --- .../java/io/ballerina/stdlib/crypto/CryptoUtils.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java index 5ad3306d..bf2cfc46 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java @@ -34,7 +34,6 @@ import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; -import org.bouncycastle.jcajce.provider.digest.Keccak; import org.bouncycastle.jcajce.spec.KEMExtractSpec; import org.bouncycastle.jcajce.spec.KEMGenerateSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -125,13 +124,8 @@ public static Object hmac(String algorithm, byte[] key, byte[] input) { */ public static byte[] hash(String algorithm, byte[] input, Object salt) { try { - MessageDigest messageDigest; - - if (Constants.KECCAK256.equals(algorithm)) { - messageDigest = new Keccak.Digest256(); - } else { - messageDigest = MessageDigest.getInstance(algorithm); - } + CryptoUtils.addBCProvider(); + MessageDigest messageDigest = MessageDigest.getInstance(algorithm); if (salt != null) { messageDigest.update(((BArray) salt).getBytes()); From eec6a5bbed5d97ff6f177d2c072bb27e04da7a09 Mon Sep 17 00:00:00 2001 From: Thilan Date: Tue, 21 Jan 2025 13:00:40 +0530 Subject: [PATCH 20/21] fix test_hash.bal --- ballerina/tests/hash_test.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/tests/hash_test.bal b/ballerina/tests/hash_test.bal index ca44810e..83543b6d 100644 --- a/ballerina/tests/hash_test.bal +++ b/ballerina/tests/hash_test.bal @@ -139,7 +139,7 @@ isolated function testHashSha512WithSalt() { isolated function testHashKeccak256() { byte[] input = "Ballerina test".toBytes(); string expectedKeccak256Hash = - "73b6cc25ab0656625ee654a6cdc8f1d1803a6330fba4f4bf5bd6b9018f7d3131".toLowerAscii(); + "73b6cc25ab0656625ee654a6cdc8f1d1803a6330fba4f4bf5bd6b9018f7d3131"; test:assertEquals(hashKeccak256(input).toBase16(), expectedKeccak256Hash); } From 4613995debe1aaf3e3accb6b7f93bbe067cdb87b Mon Sep 17 00:00:00 2001 From: MohamedSabthar Date: Tue, 21 Jan 2025 13:48:17 +0530 Subject: [PATCH 21/21] Update changelog.md --- changelog.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index cbebe5a4..36b5d22f 100644 --- a/changelog.md +++ b/changelog.md @@ -7,14 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -### Added -- [Introduce Keccak-256 hashing algorithm](https://github.com/ballerina-platform/ballerina-library/issues/7509) - -## [2.7.3] - 2025-01-20 - ### Added - [Introduce new APIs to support PGP encryption and decryption with streams](https://github.com/ballerina-platform/ballerina-library/issues/7064) - [Introduce new APIs to support Bcrypt and Argon2 hashing and verification](https://github.com/ballerina-platform/ballerina-library/issues/2744) +- [Introduce Keccak-256 hashing algorithm](https://github.com/ballerina-platform/ballerina-library/issues/7509) ## [2.7.2] - 2024-05-30