Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ private CryptomanagerConstant() {
public static final String CACHE_AES_KEY = "cacheAESKey";

public static final String CACHE_INT_COUNTER = "cacheIntCounter";

public static final byte[] VERSION_EC256_R1 = "VER_E2".getBytes(); // secp256R1 curve header

public static final byte[] VERSION_EC256_K1 = "VER_K2".getBytes(); // secp256K1 curve header

public static final byte[] VERSION_EC_X25519 = "VER_X2".getBytes(); // X25519 curve header

public static final String EC_SECP256R1 = "SECP256R1";

public static final String EC_SECP256K1 = "SECP256K1";

public static final String EC_X25519 = "X25519";

}

Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public enum CryptomanagerErrorCode {

JWE_DECRYPTION_INTERNAL_ERROR("KER-CRY-015", "Internal Error while decrypting data using JWE."),

UNSUPPORTED_EC_CURVE("KER-CRY-016", "Unsupported EC Curve Provided. Please check the curve name."),

INTERNAL_SERVER_ERROR("KER-CRY-500", "Internal server error");


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.mosip.kernel.cryptomanager.service;

import java.security.PrivateKey;
import java.security.PublicKey;

public interface EcCryptoOperation {

/**
*
* Encrypts data using an asymmetric EC public key.
*
* @param publicKey the public key to use for encryption
* @param data the data to encrypt
* @param iv the initialization vector (IV) for encryption
* @param aad additional authenticated data (AAD)
* @return the encrypted data
*/
public byte[] asymmetricEcEncrypt(PublicKey publicKey, byte[] data, byte[] iv, byte[] aad, String algorithmName);

/**
*
* Encrypts data using an asymmetric EC public key with a specified curve name.
*
* @param publicKey the public key to use for encryption
* @param data the data to encrypt
* @param curveName the name of the elliptic curve used
* @return the encrypted data
*/
public byte[] asymmetricEcEncrypt(PublicKey publicKey, byte[] data, String curveName);

/**
*
* Decrypts data using an asymmetric EC private key.
*
* @param privateKey the private key to use for decryption
* @param data the data to decrypt
* @param aad additional authenticated data (AAD)
* @param curveName the name of the elliptic curve used
* @return the decrypted data
*/
public byte[] asymmetricEcDecrypt(PrivateKey privateKey, byte[] data, byte[] aad, String curveName);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
package io.mosip.kernel.cryptomanager.service.impl;

import io.mosip.kernel.core.exception.NoSuchAlgorithmException;
import io.mosip.kernel.core.logger.spi.Logger;
import io.mosip.kernel.core.util.CryptoUtil;
import io.mosip.kernel.crypto.jce.constant.SecurityExceptionCodeConstant;
import io.mosip.kernel.crypto.jce.util.CryptoUtils;
import io.mosip.kernel.cryptomanager.constant.CryptomanagerConstant;
import io.mosip.kernel.cryptomanager.service.EcCryptoOperation;
import io.mosip.kernel.keymanagerservice.logger.KeymanagerLogger;
import io.mosip.kernel.core.crypto.exception.InvalidKeyException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Objects;

@Service
public class EcCryptoOperationImpl implements EcCryptoOperation {

private static final String AES = "AES";

@Value("${mosip.kernel.data-key-splitter}")
private String keySplitter;

@Value("${mosip.kernel.crypto.gcm-tag-length:128}")
private int tagLength;

@Value("${mosip.kernel.crypto.symmetric-algorithm-name:AES/GCM/NoPadding}")
private String symmetricAlgorithmName;

private static final Logger LOGGER = KeymanagerLogger.getLogger(CryptomanagerServiceImpl.class);

private static final String reason = "CryptoManager";

private static final int AES_KEY_LENGTH = 32; // AES-256

private static final String HMAC_SHA_256 = "HmacSHA256";

private static final String EC_ALGORITHM = "EC";

private static final String ECDH = "ECDH";


@Override
public byte[] asymmetricEcEncrypt(PublicKey key, byte[] data, String curveName) {
Objects.requireNonNull(key, SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage());
CryptoUtils.verifyData(data);
return asymmetricEcEncrypt(key, data, null, null, curveName);
}

@Override
public byte[] asymmetricEcEncrypt(PublicKey key, byte[] data, byte[] randomIV, byte[] aad, String curveName) {
byte[] output;
Cipher cipher;
SecretKey aesKey = null;
byte[] ephemeralPublicKey = null;
KeyPair ephemeralKeyPair = null;

try {
KeyPairGenerator ephemeralKeyPairGen = KeyPairGenerator.getInstance(EC_ALGORITHM);
ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(curveName);
ephemeralKeyPairGen.initialize(ecGenParameterSpec);
Comment on lines +66 to +69

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify curve routing and hard-coded algorithm usage
rg -n -C2 'EC_X25519|VERSION_EC_X25519|getHeaderByte' kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager
rg -n -C2 'asymmetricEcDecrypt\(PrivateKey privateKey, byte\[] data, byte\[] aad, String algorithmName\)|\balgorithmName\b' kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java
rg -n -C2 'KeyPairGenerator\.getInstance\(EC_ALGORITHM\)|KeyAgreement\.getInstance\(ECDH\)|KeyFactory\.getInstance\(EC_ALGORITHM\)' kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java

Repository: mosip/keymanager

Length of output: 6610


🌐 Web query:

Does Java JCA support X25519 key generation/agreement through KeyPairGenerator.getInstance("EC")+ECGenParameterSpec("X25519"), or should X25519/XDH algorithms be used explicitly?

💡 Result:

In the Java Cryptography Architecture (JCA), X25519 key generation should be performed using the "XDH" algorithm, not the "EC" algorithm [1][2]. While some specialized providers (such as the Android Keystore) may support X25519 through the "EC" algorithm for specific platform integrations [3], standard Java SE implementations require the use of "XDH" to comply with the API introduced in JEP 324 [1]. To generate an X25519 key pair, you should use the following approach: 1. Obtain a KeyPairGenerator instance for "XDH" [1]. 2. Initialize it using a NamedParameterSpec set to "X25519" [1][4]. Example: KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH"); NamedParameterSpec paramSpec = new NamedParameterSpec("X25519"); kpg.initialize(paramSpec); KeyPair kp = kpg.generateKeyPair; Using KeyPairGenerator.getInstance("X25519") is also a supported shorthand in modern Java versions [1]. The "EC" algorithm and ECGenParameterSpec are intended for traditional Elliptic Curve cryptography (such as NIST curves) and should not be used for X25519 key agreement in standard JCA code [1][2][5].

Citations:


🏁 Script executed:

# Get full implementation of EcCryptoOperationImpl to check if algorithmName is used
head -200 kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java | tail -150

Repository: mosip/keymanager

Length of output: 8083


🏁 Script executed:

# Check if algorithmName is used anywhere in the asymmetricEcDecrypt method
grep -n "algorithmName" kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java

Repository: mosip/keymanager

Length of output: 174


🏁 Script executed:

# Get full file to understand context better
wc -l kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java

Repository: mosip/keymanager

Length of output: 181


Remove unused algorithmName parameter and fix hard-coded EC/ECDH algorithm usage to support X25519.

The algorithmName parameter is unused in asymmetricEcDecrypt, and more critically, KeyPairGenerator.getInstance(EC_ALGORITHM), KeyAgreement.getInstance(ECDH), and KeyFactory.getInstance(EC_ALGORITHM) are hard-coded throughout the class. X25519 support is broken because Java JCA requires "XDH" algorithm for X25519 key generation and agreement, not "EC". The codebase has X25519 routing infrastructure with VERSION_EC_X25519 headers, but this implementation cannot honor it due to the hard-coded algorithm constraints.

This also applies to lines 134 (method signature), 154-160 (decryption's hard-coded algorithm instantiations), and the corresponding encryption methods that similarly ignore curve selection.

🧰 Tools
🪛 ast-grep (0.43.0)

[warning] 66-66: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: KeyPairGenerator.getInstance(EC_ALGORITHM)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures

(desede-is-deprecated-java)


[warning] 66-66: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: KeyPairGenerator.getInstance(EC_ALGORITHM)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures

(use-of-aes-ecb-java)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java`
around lines 66 - 69, The EcCryptoOperationImpl class has hard-coded algorithm
names that prevent X25519 support. First, remove the unused algorithmName
parameter from the asymmetricEcDecrypt method signature around line 134. Then,
replace the hard-coded algorithm strings throughout the class:
KeyPairGenerator.getInstance(EC_ALGORITHM) at line 67,
KeyAgreement.getInstance(ECDH) around lines 154-160, and
KeyFactory.getInstance(EC_ALGORITHM) need to be made dynamic based on the
curveName parameter. Create a helper method to determine the correct algorithm
(return "XDH" when curveName is X25519, otherwise return "EC" for standard
elliptic curves) and apply this logic consistently across all KeyPairGenerator,
KeyAgreement, and KeyFactory instantiation calls in the encryption and
decryption methods so X25519 routing via VERSION_EC_X25519 headers can function
properly.

ephemeralKeyPair = ephemeralKeyPairGen.generateKeyPair();

KeyAgreement keyAgreement = KeyAgreement.getInstance(ECDH);
keyAgreement.init(ephemeralKeyPair.getPrivate());
keyAgreement.doPhase(key, true);
byte[] sharedSecret = keyAgreement.generateSecret();

if (randomIV == null || randomIV.length == 0) {
randomIV = generateIV(CryptomanagerConstant.GCM_NONCE_LENGTH); // Default IV length for AES
}

byte[] aesKeyBytes = getHkdfKeyBytes(sharedSecret, randomIV, reason.getBytes(), AES_KEY_LENGTH);
aesKey = new SecretKeySpec(aesKeyBytes, 0, AES_KEY_LENGTH, AES);

GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(tagLength, randomIV);
cipher = Cipher.getInstance(symmetricAlgorithmName);
cipher.init(Cipher.ENCRYPT_MODE, aesKey, gcmParameterSpec);
if (aad != null && aad.length != 0) {
cipher.updateAAD(aad);
}

byte[] encryptedData = cipher.doFinal(data);

byte[] encryptedDataWithIv = new byte[encryptedData.length + randomIV.length];
ephemeralPublicKey = ephemeralKeyPair.getPublic().getEncoded();

System.arraycopy(encryptedData, 0, encryptedDataWithIv, 0, encryptedData.length);
System.arraycopy(randomIV, 0, encryptedDataWithIv, encryptedData.length, randomIV.length);

byte[] keySplitterBytes = keySplitter.getBytes();
output = new byte[encryptedDataWithIv.length + keySplitterBytes.length + ephemeralPublicKey.length];

System.arraycopy(encryptedDataWithIv, 0, output, 0, encryptedDataWithIv.length);
System.arraycopy(keySplitterBytes, 0, output, encryptedDataWithIv.length, keySplitterBytes.length);
System.arraycopy(ephemeralPublicKey, 0, output, encryptedDataWithIv.length + keySplitterBytes.length, ephemeralPublicKey.length);

Comment on lines +99 to +105

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Binary payload framing with keySplitter is collision-prone.

The encrypt path inserts a text delimiter into raw binary, and decrypt finds it by index scan. If ciphertext/IV bytes contain the same sequence, parsing breaks nondeterministically (wrong split, invalid key parse, decryption failures).

Protocol-hardening direction
- // output = encryptedDataWithIv + keySplitter + ephemeralPublicKey
+ // output = [4-byte encLen][encDataWithIv][4-byte ephKeyLen][ephPublicKey]
+ // Use explicit length-prefix framing to avoid delimiter collisions in binary payloads.

Also applies to: 142-147

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java`
around lines 99 - 105, Replace the delimiter-based framing using keySplitter
with length-prefixed encoding to eliminate binary collision risks. Instead of
concatenating encryptedDataWithIv, keySplitterBytes, and ephemeralPublicKey with
a text delimiter, prepend the length of each component as a fixed-size integer
prefix (e.g., 4 bytes per length field). During encryption in the
System.arraycopy operations, write component lengths before their data. During
decryption (lines 142-147), read the length prefixes to determine exact
boundaries for each component rather than scanning for the keySplitter index.
This ensures the decrypt path correctly identifies component boundaries
regardless of byte patterns in the ciphertext or IV.

} catch (java.security.NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException e) {
throw new NoSuchAlgorithmException(
SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e);
} catch (java.security.InvalidKeyException | IllegalBlockSizeException e) {
throw new InvalidKeyException(
SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e);
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidKeyException(
SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorMessage(), e);
} finally {
if (aesKey != null) {
destroyKey(aesKey.getEncoded());
}
if (ephemeralPublicKey != null) {
destroyKey(ephemeralPublicKey);
}
if (ephemeralKeyPair != null) {
destroyKey(ephemeralKeyPair.getPrivate().getEncoded());
}
if (ephemeralKeyPair.getPrivate() != null) destroyKey(ephemeralKeyPair.getPublic().getEncoded());
}
Comment on lines +125 to +129

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Avoid NPE in finally when key-pair generation fails.

Line 128 dereferences ephemeralKeyPair without guarding ephemeralKeyPair != null; if curve init/generation fails earlier, this throws NullPointerException and masks the real crypto error.

Proposed fix
-            if (ephemeralKeyPair != null) {
-                destroyKey(ephemeralKeyPair.getPrivate().getEncoded());
-            }
-            if (ephemeralKeyPair.getPrivate() != null) destroyKey(ephemeralKeyPair.getPublic().getEncoded());
+            if (ephemeralKeyPair != null) {
+                if (ephemeralKeyPair.getPrivate() != null) {
+                    destroyKey(ephemeralKeyPair.getPrivate().getEncoded());
+                }
+                if (ephemeralKeyPair.getPublic() != null) {
+                    destroyKey(ephemeralKeyPair.getPublic().getEncoded());
+                }
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (ephemeralKeyPair != null) {
destroyKey(ephemeralKeyPair.getPrivate().getEncoded());
}
if (ephemeralKeyPair.getPrivate() != null) destroyKey(ephemeralKeyPair.getPublic().getEncoded());
}
if (ephemeralKeyPair != null) {
if (ephemeralKeyPair.getPrivate() != null) {
destroyKey(ephemeralKeyPair.getPrivate().getEncoded());
}
if (ephemeralKeyPair.getPublic() != null) {
destroyKey(ephemeralKeyPair.getPublic().getEncoded());
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java`
around lines 125 - 129, The second destroyKey call on
ephemeralKeyPair.getPublic().getEncoded() in the finally block is missing a null
check guard; wrap this call with an if condition checking ephemeralKeyPair !=
null before dereferencing it, similar to the guard already present for the
private key destruction, to prevent NullPointerException if key-pair generation
fails earlier.

return output;
}

@Override
public byte[] asymmetricEcDecrypt(PrivateKey privateKey, byte[] data, byte[] aad, String algorithmName) {
Objects.requireNonNull(privateKey, SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage());
CryptoUtils.verifyData(data);
byte[] decryptedData = null;

try {
byte[] keySplitterBytes = keySplitter.getBytes();

int splitterIndex = 0;
splitterIndex = CryptoUtil.getSplitterIndex(data, splitterIndex, keySplitter);

// Extract encrypted data and ephemeral public key bytes
byte[] encryptedData = Arrays.copyOfRange(data, 0, splitterIndex);
byte[] ephemeralPublicKeyBytes = Arrays.copyOfRange(data, splitterIndex + keySplitterBytes.length, data.length);

// Extract IV from the end of encryptedData
int ivLength = CryptomanagerConstant.GCM_NONCE_LENGTH;
byte[] iv = Arrays.copyOfRange(encryptedData, encryptedData.length - ivLength, encryptedData.length);
byte[] cipherText = Arrays.copyOfRange(encryptedData, 0, encryptedData.length - ivLength);

KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(ephemeralPublicKeyBytes);
PublicKey ephemeralPublicKey = keyFactory.generatePublic(publicKeySpec);

KeyAgreement keyAgreement = KeyAgreement.getInstance(ECDH);
keyAgreement.init(privateKey);
keyAgreement.doPhase(ephemeralPublicKey, true);
byte[] sharedSecret = keyAgreement.generateSecret();

byte[] aesKeyBytes = getHkdfKeyBytes(sharedSecret, iv, reason.getBytes(), AES_KEY_LENGTH);
SecretKey aesKey = new SecretKeySpec(aesKeyBytes, 0, AES_KEY_LENGTH, AES);

Cipher aesCipher = Cipher.getInstance(symmetricAlgorithmName);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(tagLength, iv);
aesCipher.init(Cipher.DECRYPT_MODE, aesKey, gcmParameterSpec);
if (aad != null && aad.length != 0) {
aesCipher.updateAAD(aad);
}
decryptedData = aesCipher.doFinal(cipherText);

} catch (java.security.NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException e) {
throw new NoSuchAlgorithmException(
SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e);
} catch (java.security.InvalidKeyException | java.security.spec.InvalidKeySpecException | IllegalBlockSizeException e) {
throw new InvalidKeyException(
SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e);
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidKeyException(
SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorMessage(), e);
}
return decryptedData;
}

/**
* Generator for IV (Initialization Vector)
*
* @param blockSize blocksize of current cipher
* @return generated IV
*/
private byte[] generateIV(int blockSize) {
byte[] byteIV = new byte[blockSize];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(byteIV);
return byteIV;
}

/**
* Destroys the key by filling it with zeros.
*
* @param key The key to be destroyed.
*/
private void destroyKey(byte[] key) {
if (Objects.nonNull(key)) {
Arrays.fill(key, (byte) 0);
}
}

/**
* Generates HKDF key bytes using the provided secret, salt, reason, and key length.
*
* @param ikm The Input Key Material (IKM) to derive the key from.
* @param salt The salt to use in the HKDF process.
* @param reason The reason for generating the key, used as additional data.
* @param keyLength The desired length of the generated key in bytes.
* @return The derived key bytes.
*/
private byte[] getHkdfKeyBytes(byte[] ikm, byte[] salt, byte[] reason, int keyLength) {
LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.WHITESPACE, CryptomanagerConstant.WHITESPACE,
"Generating HKDF key bytes.");

try {
Mac mac = Mac.getInstance(HMAC_SHA_256);
SecretKeySpec secretKeySpec = new SecretKeySpec(salt, HMAC_SHA_256);
mac.init(secretKeySpec);
byte[] prk = mac.doFinal(ikm);

byte[] result = new byte[keyLength];
byte[] previousBlock = new byte[0];
int bytegenerated = 0;
int iteration = (int) Math.ceil((double) keyLength / mac.getMacLength());

for (int i = 0; i < iteration; i++) {
mac.init(new SecretKeySpec(prk, HMAC_SHA_256));
mac.update(previousBlock);
mac.update(reason);
mac.update((byte) (i + 1));
byte[] block = mac.doFinal();

int bytesToCopy = Math.min(block.length, keyLength - bytegenerated);
System.arraycopy(block, 0, result, bytegenerated, bytesToCopy);
bytegenerated += bytesToCopy;

previousBlock = block;
System.out.println("Number of iterations: " + (i + 1) + ", Bytes generated so far: " + bytegenerated);
}
return result;

} catch (java.security.NoSuchAlgorithmException e) {
throw new NoSuchAlgorithmException(
SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e);
} catch (java.security.InvalidKeyException e) {
throw new InvalidKeyException(
SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(),
SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e);
}
}
}
Loading
Loading