diff --git a/README.md b/README.md index 0ab9206f..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 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 diff --git a/ballerina/README.md b/ballerina/README.md index 54195ce9..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` module supports generating hashes with 5 different hash algorithms MD5, SHA1, SHA256, SHA384, and SHA512. 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 diff --git a/ballerina/hash.bal b/ballerina/hash.bal index e18ba338..3fb4671a 100644 --- a/ballerina/hash.bal +++ b/ballerina/hash.bal @@ -105,6 +105,21 @@ public isolated function crc32b(byte[] input) returns string = @java:Method { '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; + # Returns a BCrypt hash of the given password with optional work factor. # ```ballerina # string password = "mySecurePassword123"; @@ -164,4 +179,3 @@ public isolated function verifyArgon2(string password, string hashedPassword) re name: "verifyPasswordArgon2", 'class: "io.ballerina.stdlib.crypto.nativeimpl.PasswordArgon2" } external; - diff --git a/ballerina/tests/hash_test.bal b/ballerina/tests/hash_test.bal index 4ec03748..83543b6d 100644 --- a/ballerina/tests/hash_test.bal +++ b/ballerina/tests/hash_test.bal @@ -134,6 +134,15 @@ isolated function testHashSha512WithSalt() { test:assertEquals(hashSha512(input, salt).toBase16(), expectedSha512Hash); } + +@test:Config {} +isolated function testHashKeccak256() { + byte[] input = "Ballerina test".toBytes(); + string expectedKeccak256Hash = + "73b6cc25ab0656625ee654a6cdc8f1d1803a6330fba4f4bf5bd6b9018f7d3131"; + test:assertEquals(hashKeccak256(input).toBase16(), expectedKeccak256Hash); +} + // tests for Argon2 @test:Config {} isolated function testHashPasswordArgon2Default() returns error? { diff --git a/changelog.md b/changelog.md index 60e1fc3e..36b5d22f 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### 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 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[]; +``` diff --git a/docs/spec/spec.md b/docs/spec/spec.md index 5151d2d1..4fef99eb 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) @@ -168,6 +169,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. 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"; } 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..bf2cfc46 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/CryptoUtils.java @@ -124,7 +124,9 @@ 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); + CryptoUtils.addBCProvider(); + MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + if (salt != null) { messageDigest.update(((BArray) salt).getBytes()); } 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..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,23 +46,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(Constants.MD5, 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(Constants.SHA1, 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(Constants.SHA256, 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(Constants.SHA384, 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(Constants.SHA512, inputValue.getBytes(), saltValue)); } + public static BArray hashKeccak256(BArray inputValue, Object saltValue) { + return ValueCreator.createArrayValue(CryptoUtils.hash(Constants.KECCAK256, inputValue.getBytes(), saltValue)); + } }