diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java index b5ef146e..600a4837 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java @@ -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"; } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java index 094a0d69..909b1288 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java @@ -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"); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/EcCryptoOperation.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/EcCryptoOperation.java new file mode 100644 index 00000000..c57de11e --- /dev/null +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/EcCryptoOperation.java @@ -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); +} diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java index bb02eab7..d51e151b 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java @@ -16,9 +16,13 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import io.mosip.kernel.crypto.jce.core.CryptoCore; +import io.mosip.kernel.cryptomanager.service.EcCryptoOperation; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; import jakarta.annotation.PostConstruct; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -118,6 +122,9 @@ public class CryptomanagerServiceImpl implements CryptomanagerService { @Value("${mosip.keymanager.argon2.hash.generate.parallelism:2}") private int argon2Parallelism; + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String ecCurveName; + private static SecureRandom secureRandom = null; /** @@ -144,8 +151,12 @@ public class CryptomanagerServiceImpl implements CryptomanagerService { @Autowired KeymanagerUtil keymanagerUtil; + @Autowired + EcCryptoOperation ecCryptoOperation; + private Cache saltGenParamsCache = null; + @PostConstruct public void init() { // Added Cache2kBuilder in the postConstruct because expire value @@ -180,60 +191,86 @@ public void init() { /* * (non-Javadoc) - * + * * @see * io.mosip.kernel.cryptography.service.CryptographyService#encrypt(io.mosip. * kernel.cryptography.dto.CryptographyRequestDto) */ @Override public CryptomanagerResponseDto encrypt(CryptomanagerRequestDto cryptoRequestDto) { - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, - "Request for data encryption."); - + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Request for data encryption."); + cryptomanagerUtil.validateKeyIdentifierIds(cryptoRequestDto.getApplicationId(), cryptoRequestDto.getReferenceId()); - SecretKey secretKey = keyGenerator.getSymmetricKey(); - final byte[] encryptedData; - byte[] headerBytes = new byte[0]; - if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { - encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); - } else { - byte[] aad = cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad())); - if (aad == null || aad.length == 0){ - encryptedData = generateAadAndEncryptData(secretKey, cryptoRequestDto.getData()); - headerBytes = CryptomanagerConstant.VERSION_RSA_2048; - } else { - encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), - aad); - } - } Certificate certificate = cryptomanagerUtil.getCertificate(cryptoRequestDto); - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, - "Found the cerificate, proceeding with session key encryption."); PublicKey publicKey = certificate.getPublicKey(); - final byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(publicKey, secretKey.getEncoded()); - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, - "Session key encryption completed."); - //boolean prependThumbprint = cryptoRequestDto.getPrependThumbprint() == null ? false : cryptoRequestDto.getPrependThumbprint(); + byte[] certThumbprint = cryptomanagerUtil.getCertificateThumbprint(certificate); + CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); - // support of 1.1.3 no thumbprint is configured as true & encryption request with no thumbprint - // request thumbprint flag will not be considered if support no thumbprint is set to false. - //------------------- - // no thumbprint flag will not be required to consider at the time of encryption. So commented the below code. - // from 1.2.0.1 version, support of no thumbprint flag will be removed in case of data encryption. + + if (publicKey.getAlgorithm().equalsIgnoreCase(io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.RSA)) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.RSA, + "Encrypting the Data Using RSA key."); + SecretKey secretKey = keyGenerator.getSymmetricKey(); + final byte[] encryptedData; + byte[] headerBytes = new byte[0]; + if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { + encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); + } else { + byte[] aad = cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad())); + if (aad == null || aad.length == 0){ + encryptedData = generateAadAndEncryptData(secretKey, cryptoRequestDto.getData()); + headerBytes = CryptomanagerConstant.VERSION_RSA_2048; + } else { + encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), + aad); + } + } + + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Found the cerificate, proceeding with session key encryption."); + final byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(publicKey, secretKey.getEncoded()); + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Session key encryption completed."); + //boolean prependThumbprint = cryptoRequestDto.getPrependThumbprint() == null ? false : cryptoRequestDto.getPrependThumbprint(); + // support of 1.1.3 no thumbprint is configured as true & encryption request with no thumbprint + // request thumbprint flag will not be considered if support no thumbprint is set to false. + //------------------- + // no thumbprint flag will not be required to consider at the time of encryption. So commented the below code. + // from 1.2.0.1 version, support of no thumbprint flag will be removed in case of data encryption. /* if (noThumbprint && !prependThumbprint) { byte[] finalEncKeyBytes = cryptomanagerUtil.concatByteArrays(headerBytes, encryptedSymmetricKey); cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(encryptedData, finalEncKeyBytes, keySplitter))); return cryptoResponseDto; - } */ - //--------------------- - byte[] certThumbprint = cryptomanagerUtil.getCertificateThumbprint(certificate); - byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedSymmetricKey); - byte[] finalEncKeyBytes = cryptomanagerUtil.concatByteArrays(headerBytes, concatedData); - cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(encryptedData, - finalEncKeyBytes, keySplitter))); + } */ + //--------------------- + byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedSymmetricKey); + byte[] finalEncKeyBytes = cryptomanagerUtil.concatByteArrays(headerBytes, concatedData); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(encryptedData, + finalEncKeyBytes, keySplitter))); + } else { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, KeymanagerConstant.EC_KEY_TYPE, + "Encrypting the Data Using ECC key."); + + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Found the cerificate, proceeding with ecc key encryption."); + + byte[] aad = cryptomanagerUtil.generateRandomBytes(CryptomanagerConstant.GCM_AAD_LENGTH); + byte[] encryptedData = ecCryptoOperation.asymmetricEcEncrypt(publicKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), null, aad, ecCurveName); + byte[] encryptedDataWithIv = cryptomanagerUtil.concatByteArrays(aad, encryptedData); + + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "ECC key encryption completed."); + + byte[] headerBytes = cryptomanagerUtil.getHeaderByte(ecCurveName); + + byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedDataWithIv); + byte[] finalEncKeyBytes = CryptoUtil.combineByteArray(concatedData, headerBytes, keySplitter); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(finalEncKeyBytes)); + } return cryptoResponseDto; } @@ -249,14 +286,14 @@ private byte[] generateAadAndEncryptData(SecretKey secretKey, String data){ /* * (non-Javadoc) - * + * * @see * io.mosip.kernel.cryptography.service.CryptographyService#decrypt(io.mosip. * kernel.cryptography.dto.CryptographyRequestDto) */ @Override public CryptomanagerResponseDto decrypt(CryptomanagerRequestDto cryptoRequestDto) { - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, "Request for data decryption."); boolean hasAcccess = cryptomanagerUtil.hasKeyAccess(cryptoRequestDto.getApplicationId()); @@ -269,32 +306,56 @@ public CryptomanagerResponseDto decrypt(CryptomanagerRequestDto cryptoRequestDto int keyDemiliterIndex = 0; byte[] encryptedHybridData = cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()); keyDemiliterIndex = CryptoUtil.getSplitterIndex(encryptedHybridData, keyDemiliterIndex, keySplitter); - byte[] encryptedKey = copyOfRange(encryptedHybridData, 0, keyDemiliterIndex); - byte[] encryptedData = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length(), - encryptedHybridData.length); - - byte[] headerBytes = cryptomanagerUtil.parseEncryptKeyHeader(encryptedKey); - cryptoRequestDto.setData(CryptoUtil.encodeToURLSafeBase64(copyOfRange(encryptedKey, headerBytes.length, encryptedKey.length))); - SecretKey decryptedSymmetricKey = cryptomanagerUtil.getDecryptedSymmetricKey(cryptoRequestDto); - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, - "Session Key Decryption completed."); - final byte[] decryptedData; - if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { - decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); - } else { - if (Arrays.equals(headerBytes, CryptomanagerConstant.VERSION_RSA_2048)) { - decryptedData = splitAadAndDecryptData(decryptedSymmetricKey, encryptedData); - } else { + String algorithmName = cryptomanagerUtil.getAlgorithmNameFromHeader(encryptedHybridData); + CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); + + if (algorithmName.equalsIgnoreCase(io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.RSA)) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, KeymanagerConstant.RSA, + "Decrytping the data with RSA Key."); + + byte[] encryptedKey = copyOfRange(encryptedHybridData, 0, keyDemiliterIndex); + byte[] encryptedData = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length(), + encryptedHybridData.length); + + byte[] headerBytes = cryptomanagerUtil.parseEncryptKeyHeader(encryptedKey); + cryptoRequestDto.setData(CryptoUtil.encodeToURLSafeBase64(copyOfRange(encryptedKey, headerBytes.length, encryptedKey.length))); + SecretKey decryptedSymmetricKey = cryptomanagerUtil.getDecryptedSymmetricKey(cryptoRequestDto); + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + "Session Key Decryption completed."); + final byte[] decryptedData; + if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); + } else { + if (Arrays.equals(headerBytes, CryptomanagerConstant.VERSION_RSA_2048)) { + decryptedData = splitAadAndDecryptData(decryptedSymmetricKey, encryptedData); + } else { + decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); + } } - } - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, - "Data decryption completed."); - CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); - cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(decryptedData)); + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + "Data decryption completed."); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(decryptedData)); + } else { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, KeymanagerConstant.EC_KEY_TYPE, + "Decrytping the data with EC Key."); + String ecCurveName = algorithmName; + byte[] thumbprint = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length(), keyDemiliterIndex + keySplitter.length() + CryptomanagerConstant.THUMBPRINT_LENGTH); + byte[] encryptedDataWithIv = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length() + CryptomanagerConstant.THUMBPRINT_LENGTH, + encryptedHybridData.length); + + String certThumbprintHex = Hex.toHexString(thumbprint).toUpperCase(); + PrivateKey privateKey = (PrivateKey) cryptomanagerUtil.getEncryptedPrivateKey(cryptoRequestDto.getApplicationId(), + Optional.ofNullable(cryptoRequestDto.getReferenceId()), certThumbprintHex)[0]; + + byte[] aad = Arrays.copyOfRange(encryptedDataWithIv, 0, CryptomanagerConstant.GCM_AAD_LENGTH); + byte[] encryptedData = Arrays.copyOfRange(encryptedDataWithIv, CryptomanagerConstant.GCM_AAD_LENGTH,encryptedDataWithIv.length); + + byte[] decryptedData = ecCryptoOperation.asymmetricEcDecrypt(privateKey, encryptedData, aad, ecCurveName); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(decryptedData)); + } return cryptoResponseDto; } @@ -625,5 +686,4 @@ private byte[] getSaltBytes(byte[] randomBytes, SecretKey aesKey) { return bytes; } - } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java new file mode 100644 index 00000000..c90f5e60 --- /dev/null +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptoOperationImpl.java @@ -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); + 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); + + } 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()); + } + 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); + } + } +} diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java index 29d6feff..359dc16e 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java @@ -7,17 +7,15 @@ package io.mosip.kernel.cryptomanager.util; import java.io.IOException; -import java.security.PublicKey; -import java.security.SecureRandom; +import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -27,6 +25,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; +import io.mosip.kernel.core.keymanager.spi.ECKeyStore; +import io.mosip.kernel.core.util.DateUtils; +import io.mosip.kernel.keymanagerservice.constant.KeyReferenceIdConsts; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerErrorConstant; +import io.mosip.kernel.keymanagerservice.entity.KeyAlias; +import io.mosip.kernel.keymanagerservice.exception.NoUniqueAliasException; +import io.mosip.kernel.keymanagerservice.helper.PrivateKeyDecryptorHelper; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.annotation.Autowired; @@ -95,6 +100,13 @@ public class CryptomanagerUtils { @Value("${mosip.kernel.keymanager.jwtEncrypt.validate.json:true}") private boolean confValidateJson; + /** The sign applicationid. */ + @Value("${mosip.sign.applicationid:KERNEL}") + private String signApplicationid; + + @Value("${mosip.sign-certificate-refid:SIGN}") + private String certificateSignRefID; + /** The key manager. */ @Autowired private KeymanagerService keyManager; @@ -105,6 +117,16 @@ public class CryptomanagerUtils { @Autowired private KeymanagerDBHelper dbHelper; + @Autowired + private ECKeyStore keyStore; + + @Autowired + private PrivateKeyDecryptorHelper privateKeyDecryptorHelper; + + /** Flag to generate and store Ed25519 key in real HSM. */ + @Value("${mosip.kernel.keymanager.ed25519.hsm.support.enabled:false}") + private boolean ed25519SupportFlag; + /** * Calls Key-Manager-Service to get public key of an application. * @@ -125,7 +147,7 @@ public Certificate getCertificate(CryptomanagerRequestDto cryptomanagerRequestDt * @param refId the ref id * @return the certificate data from key manager */ - private String getCertificateFromKeyManager(String appId, String refId) { + public String getCertificateFromKeyManager(String appId, String refId) { return keyManager.getCertificate(appId, Optional.ofNullable(refId)).getCertificate(); } @@ -229,12 +251,12 @@ public String getCertificateThumbprintInHex(Certificate cert) { return Hex.toHexString(getCertificateThumbprint(cert)).toUpperCase(); } - public byte[] concatCertThumbprint(byte[] certThumbprint, byte[] encryptedKey){ - byte[] finalData = new byte[CryptomanagerConstant.THUMBPRINT_LENGTH + encryptedKey.length]; - System.arraycopy(certThumbprint, 0, finalData, 0, certThumbprint.length); - System.arraycopy(encryptedKey, 0, finalData, certThumbprint.length, encryptedKey.length); - return finalData; - } + public byte[] concatCertThumbprint(byte[] certThumbprint, byte[] encryptedKey){ + byte[] finalData = new byte[CryptomanagerConstant.THUMBPRINT_LENGTH + encryptedKey.length]; + System.arraycopy(certThumbprint, 0, finalData, 0, certThumbprint.length); + System.arraycopy(encryptedKey, 0, finalData, certThumbprint.length, encryptedKey.length); + return finalData; + } public byte[] generateRandomBytes(int size) { byte[] randomBytes = new byte[size]; @@ -258,6 +280,24 @@ public byte[] parseEncryptKeyHeader(byte[] encryptedKey){ return versionHeaderBytes; } + public String getAlgorithmNameFromHeader(byte[] encryptedData) { + int keyDelimiterIndex = 0; + keyDelimiterIndex = CryptoUtil.getSplitterIndex(encryptedData, keyDelimiterIndex, keySplitter); + byte[] algorithmBytes = Arrays.copyOfRange(encryptedData, 0, keyDelimiterIndex); + String algorithmName; + + if (Arrays.equals(algorithmBytes, CryptomanagerConstant.VERSION_EC256_R1)) { + algorithmName = CryptomanagerConstant.EC_SECP256R1; + } else if (Arrays.equals(algorithmBytes, CryptomanagerConstant.VERSION_EC256_K1)) { + algorithmName = CryptomanagerConstant.EC_SECP256K1; + } else if (Arrays.equals(algorithmBytes, CryptomanagerConstant.VERSION_EC_X25519)) { + algorithmName = CryptomanagerConstant.EC_X25519; + } else { + algorithmName = KeymanagerConstant.RSA; + } + return algorithmName; + } + public boolean isDataValid(String anyData) { return anyData != null && !anyData.trim().isEmpty(); } @@ -392,4 +432,107 @@ public void validateInputData(String reqDataToDigest) { } } + public Object[] getEncryptedPrivateKey(String appId, Optional refId, String certThumbprint) { + + LocalDateTime localDateTime = DateUtils.getUTCCurrentDateTime(); + Map> keyAliasMap = dbHelper.getKeyAliases(appId, refId.get(), localDateTime); + KeyAlias keyAlias = keyAliasMap.get(KeymanagerConstant.CURRENTKEYALIAS).getFirst(); + String ksAlias = keyAlias.getAlias(); + + if (!refId.isPresent() || refId.get().trim().isEmpty()) { + LOGGER.info(KeymanagerConstant.SESSIONID, KeymanagerConstant.EMPTY, KeymanagerConstant.EMPTY, + "Not valid reference Id. Getting private key from HSM."); + KeyStore.PrivateKeyEntry masterKeyEntry = keyStore.getAsymmetricKey(ksAlias); + PrivateKey masterPrivateKey = masterKeyEntry.getPrivateKey(); + Certificate masterCert = masterKeyEntry.getCertificate(); + return new Object[] {masterPrivateKey, masterCert}; + + } else if ((appId.equalsIgnoreCase(signApplicationid) && refId.isPresent() + && refId.get().equals(certificateSignRefID)) || + (refId.isPresent() && refId.get().equals(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name())) || + (refId.isPresent() && refId.get().equals(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name())) || + (refId.isPresent() && refId.get().equals(KeyReferenceIdConsts.ED25519_SIGN.name()) + && ed25519SupportFlag)) { + LOGGER.info(KeymanagerConstant.SESSIONID, KeymanagerConstant.EMPTY, KeymanagerConstant.EMPTY, + "Reference Id is present and it is " + refId.get() + " Signature Key ref Id. Getting private key from HSM."); + KeyStore.PrivateKeyEntry masterKeyEntry = keyStore.getAsymmetricKey(ksAlias); + PrivateKey masterPrivateKey = masterKeyEntry.getPrivateKey(); + Certificate masterCert = masterKeyEntry.getCertificate(); + return new Object[] {masterPrivateKey, masterCert}; + } else { + LOGGER.info(KeymanagerConstant.SESSIONID, KeymanagerConstant.EMPTY, KeymanagerConstant.EMPTY, + "Reference Id is present. Will get Certificate from DB store"); + + String referenceId = refId.get(); + io.mosip.kernel.keymanagerservice.entity.KeyStore dbKeyStore = privateKeyDecryptorHelper.getDBKeyStoreData(certThumbprint, + appId, referenceId); + if (dbKeyStore.getAlias().isEmpty()) { + LOGGER.error(KeymanagerConstant.SESSIONID, KeymanagerConstant.KEYFROMDB, dbKeyStore.toString(), + "Key in DBStore does not exist for this alias. Throwing exception"); + throw new NoUniqueAliasException(KeymanagerErrorConstant.NO_UNIQUE_ALIAS.getErrorCode(), + KeymanagerErrorConstant.NO_UNIQUE_ALIAS.getErrorMessage()); + } + String masterKeyAlias = dbKeyStore.getMasterAlias(); + String privateKeyObj = dbKeyStore.getPrivateKey(); + + if (ksAlias.equals(masterKeyAlias) || privateKeyObj.equals(KeymanagerConstant.KS_PK_NA)) { + LOGGER.error(KeymanagerConstant.SESSIONID, KeymanagerConstant.APPLICATIONID, null, + "Not Allowed to perform decryption with other domain key."); + throw new KeymanagerServiceException(KeymanagerErrorConstant.DECRYPTION_NOT_ALLOWED.getErrorCode(), + KeymanagerErrorConstant.DECRYPTION_NOT_ALLOWED.getErrorMessage()); + } + + KeyStore.PrivateKeyEntry masterKeyEntry = keyStore.getAsymmetricKey(dbKeyStore.getMasterAlias()); + PrivateKey masterPrivateKey = masterKeyEntry.getPrivateKey(); + PublicKey masterPublicKey = masterKeyEntry.getCertificate().getPublicKey(); + /** + * If the private key is in dbstore, then it will be first decrypted with + * application's master private key from softhsm's/HSM's keystore + */ + try { + return getObjects(dbKeyStore, masterPrivateKey, masterPublicKey); + } catch (Exception e) { + // need confirm the error message and code + LOGGER.error(KeymanagerConstant.SESSIONID, KeymanagerConstant.APPLICATIONID, null, + "Error while decrypting private key from DBStore. Throwing exception", e); + throw new KeymanagerServiceException(KeymanagerErrorConstant.NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + KeymanagerErrorConstant.NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage()); + } + } + } + + public Object[] getObjects(io.mosip.kernel.keymanagerservice.entity.KeyStore dbKeyStore, PrivateKey masterPrivateKey, PublicKey masterPublicKey) { + byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeURLSafeBase64(dbKeyStore.getPrivateKey()), + masterPrivateKey, masterPublicKey); + + PublicKey publicKey = keymanagerUtil.convertToCertificate(dbKeyStore.getCertificateData()).getPublicKey(); + String algorithmName = publicKey.getAlgorithm(); + KeyFactory keyFactory = null; + PrivateKey privateKey = null; + try { + keyFactory = KeyFactory.getInstance(algorithmName); + privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + Certificate certificate = keymanagerUtil.convertToCertificate(dbKeyStore.getCertificateData()); + return new Object[]{privateKey, certificate}; + } + + public byte[] getHeaderByte(String ecCurveName) { + byte[] headerBytes = new byte[0]; + if (ecCurveName.equalsIgnoreCase(CryptomanagerConstant.EC_SECP256R1)) { + headerBytes = CryptomanagerConstant.VERSION_EC256_R1; + } else if (ecCurveName.equalsIgnoreCase(CryptomanagerConstant.EC_SECP256K1)) { + headerBytes = CryptomanagerConstant.VERSION_EC256_K1; + } else if (ecCurveName.equalsIgnoreCase(CryptomanagerConstant.EC_X25519)) { + headerBytes = CryptomanagerConstant.VERSION_EC_X25519; + } else { + LOGGER.error(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Unsupported EC Curve Name: " + ecCurveName); + throw new CryptoManagerSerivceException(CryptomanagerErrorCode.UNSUPPORTED_EC_CURVE.getErrorCode(), + CryptomanagerErrorCode.UNSUPPORTED_EC_CURVE.getErrorMessage() + ecCurveName); + } + return headerBytes; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java index a3db18cc..f228e186 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java @@ -67,6 +67,10 @@ public class KeyGenerator { @Value("${mosip.kernel.keygenerator.asymmetric.ed25519.algorithm-name:Ed25519}") private String asymmetricEDKeyAlgorithm; + /** ECC algorithm curve name */ + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String eccCurve; + @Autowired private ECKeyStore keyStore; @@ -84,14 +88,24 @@ public SecretKey getSymmetricKey() { /** * This method generated Asymmetric key pairs * - * @return {@link KeyPair} which contain public nad private key + * @return {@link KeyPair} which contain public and private key */ public KeyPair getAsymmetricKey() { - KeyPairGenerator generator = KeyGeneratorUtils.getKeyPairGenerator(asymmetricKeyAlgorithm, asymmetricKeyLength, + KeyPairGenerator generator = KeyGeneratorUtils.getKeyPairGenerator(asymmetricKeyAlgorithm, asymmetricKeyLength, getSecureRandom()); return generator.generateKeyPair(); } + /** + * This method generated Asymmetric key pairs for ECC + * + * @return {@link KeyPair} which contain public and private key + */ + public KeyPair getECKeyPair() { + KeyPairGenerator generator = KeyGeneratorUtils.getECKeyPairGenerator(asymmetricKeyAlgorithm, eccCurve, getSecureRandom()); + return generator.generateKeyPair(); + } + public KeyPair getEd25519KeyPair() { KeyPairGenerator generator = KeyGeneratorUtils.getEdKeyPairGenerator(asymmetricEDKeyAlgorithm, getSecureRandom()); return generator.generateKeyPair(); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java index 52669a07..0232ab90 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java @@ -19,6 +19,7 @@ import io.mosip.kernel.core.exception.NoSuchAlgorithmException; import io.mosip.kernel.keygenerator.bouncycastle.constant.KeyGeneratorExceptionConstant; import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; +import org.springframework.beans.factory.annotation.Value; /** * This is a utils class for keygenerator @@ -105,6 +106,19 @@ public static KeyPairGenerator getEdKeyPairGenerator(String algorithmName, Secur } + public static KeyPairGenerator getECKeyPairGenerator(String algorithmName, String eccCurve, SecureRandom secureRandom) { + KeyPairGenerator generator = null; + try { + generator = KeyPairGenerator.getInstance(algorithmName, provider); + generator.initialize(new ECGenParameterSpec(eccCurve), secureRandom); + return generator; + } catch (java.security.NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { + throw new NoSuchAlgorithmException( + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } + } + public static PrivateKey generatePrivate(String algorithmName, byte[] privateKeyData) { try { return KeyFactory.getInstance(algorithmName, provider).generatePrivate(new PKCS8EncodedKeySpec(privateKeyData)); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java index 2679602e..4c3531bc 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java @@ -66,4 +66,10 @@ private KeymanagerConstant() { public static final String ASYM_KEY_ED_ALGORITHM = "ASYM_KEY_ED_ALGORITHM"; + public static final String RSA_SIGN_ALGORITHM = "SHA256withRSA"; + + public static final String EC_SIGN_ALGORITHM = "SHA256withECDSA"; + + public static final String ED_SIGN_ALGORITHM = "Ed25519"; + } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java index c63a3ee9..84675a97 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java @@ -476,7 +476,7 @@ private KeyPair generateKeyPair(String keyType) { .collect(Collectors.toList()); if (KeymanagerConstant.RSA_KEY_TYPE.equals(keyType)) return generateRSAKeyPair(); - else if (ecCurvesList.contains(keyType)) + else if (ecCurvesList.contains(keyType.toUpperCase())) return generateECKeyPair(keyType); else if (KeymanagerConstant.ED25519_KEY_TYPE.equals(keyType)) return generateEd25519KeyPair(); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java index d2fe2ba9..cebafe4d 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java @@ -15,6 +15,7 @@ import javax.security.auth.x500.X500Principal; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameBuilder; @@ -35,6 +36,7 @@ import io.mosip.kernel.core.keymanager.exception.KeystoreProcessingException; import io.mosip.kernel.core.keymanager.model.CertificateParameters; import io.mosip.kernel.keymanager.hsm.constant.KeymanagerErrorCode; +import org.springframework.beans.factory.annotation.Value; /** * Certificate utility to generate and sign X509 Certificate @@ -45,7 +47,6 @@ */ public class CertificateUtility { - /** * Private constructor for CertificateUtility */ @@ -97,7 +98,7 @@ public static X509Certificate generateX509Certificate(PrivateKey signPrivateKey, if (certSubject.equals(certIssuer)) { basicConstraints = new BasicConstraints(2); } - return generateX509Certificate(signPrivateKey, publicKey, certIssuer, certSubject, signAlgorithm, providerName, + return generateX509Certificate(signPrivateKey, publicKey, certIssuer, certSubject, getSignatureAlgorithm(signPrivateKey), providerName, certParams.getNotBefore(), certParams.getNotAfter(), keyUsage, basicConstraints); } @@ -106,8 +107,8 @@ private static X509Certificate generateX509Certificate(PrivateKey signPrivateKey BasicConstraints basicConstraints) { try { BigInteger certSerialNum = new BigInteger(Long.toString(new SecureRandom().nextLong())); - - ContentSigner certContentSigner = new JcaContentSignerBuilder(signAlgorithm).setProvider(providerName).build(signPrivateKey); + + ContentSigner certContentSigner = new JcaContentSignerBuilder(getSignatureAlgorithm(signPrivateKey)).setProvider(providerName).build(signPrivateKey); X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(certIssuer, certSerialNum, getDateFromLocalDateTime(notBefore), getDateFromLocalDateTime(notAfter), certSubject, publicKey); JcaX509ExtensionUtils certExtUtils = new JcaX509ExtensionUtils(); @@ -188,4 +189,17 @@ private static void addRDN(String dnValue, X500NameBuilder builder, ASN1ObjectId if (dnValue != null && !dnValue.isEmpty()) builder.addRDN(identifier, dnValue); } + + private static String getSignatureAlgorithm(PrivateKey privateKey) { + + String keyAlgorithm = privateKey.getAlgorithm(); + if (keyAlgorithm.equals(KeymanagerConstant.EC_KEY_TYPE)) + return io.mosip.kernel.keymanager.hsm.constant.KeymanagerConstant.EC_SIGN_ALGORITHM; + else if (keyAlgorithm.equals(KeymanagerConstant.ED25519_KEY_TYPE) || + keyAlgorithm.equals(KeymanagerConstant.ED25519_ALG_OID) || + keyAlgorithm.equals(KeymanagerConstant.EDDSA_KEY_TYPE)) + return io.mosip.kernel.keymanager.hsm.constant.KeymanagerConstant.ED_SIGN_ALGORITHM; + + return io.mosip.kernel.keymanager.hsm.constant.KeymanagerConstant.RSA_SIGN_ALGORITHM; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java index 7599c90d..e386c020 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java @@ -1,5 +1,6 @@ package io.mosip.kernel.keymanagerservice.constant; +import java.security.PublicKey; import java.time.format.DateTimeFormatter; /** @@ -226,4 +227,8 @@ private KeymanagerConstant() { public static final String ED25519_ALG_OID = "1.3.101.112"; public static final String APP_REF_ID_SEP = "#"; + + public static final String EC_SECP256R1_OID = "1.2.840.10045.3.1.7"; + + public static final String EC_SECP256K1_OID = "1.3.132.0.10"; } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java index 923f3337..60fade1e 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java @@ -378,7 +378,7 @@ private Object[] getPrivateKey(String referenceId, KeyAlias fetchedKeyAlias) { try { byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeURLSafeBase64(dbKeyStore.get().getPrivateKey()), masterPrivateKey, masterPublicKey); - KeyFactory keyFactory = KeyFactory.getInstance(KeymanagerConstant.RSA); + KeyFactory keyFactory = KeyFactory.getInstance(masterPrivateKey.getAlgorithm()); PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); Certificate certificate = keymanagerUtil.convertToCertificate(dbKeyStore.get().getCertificateData()); return new Object[] {privateKey, certificate}; diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java index 12c6f336..d232e4ef 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java @@ -18,7 +18,6 @@ import java.util.Objects; import java.util.Optional; import java.util.UUID; -import java.util.stream.Stream; import javax.security.auth.x500.X500Principal; @@ -120,6 +119,13 @@ public class KeymanagerServiceImpl implements KeymanagerService { @Value("${mosip.kernel.keymanager.ed25519.hsm.support.enabled:false}") private boolean ed25519SupportFlag; + /** Master Key generation algorithm */ + @Value("${mosip.kernel.keygenerator.asymmetric-algorithm-name:RSA}") + private String masterKeyAlgorithm; + + /** ECC algorithm curve name */ + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String eccCurve; /** * Keystore instance to handles and store cryptographic keys. @@ -157,7 +163,7 @@ public class KeymanagerServiceImpl implements KeymanagerService { @Autowired private ECKeyPairGenRequestValidator ecKeyPairGenRequestValidator; - private static Map ecRefIdsAlgoNamesMap = new HashMap<>(); + private static final Map ecRefIdsAlgoNamesMap = new HashMap<>(); static { ecRefIdsAlgoNamesMap.put(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name(), ECCurves.SECP256K1.name()); @@ -223,7 +229,12 @@ private ImmutablePair generateKeyPairInHSM(String alias X500Principal latestCertPrincipal = getLatestCertPrincipal(keyAlias); CertificateParameters certParams = keymanagerUtil.getCertificateParameters(latestCertPrincipal, generationDateTime, expiryDateTime); - keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + if (!masterKeyAlgorithm.equals(KeymanagerConstant.RSA) || (Arrays.stream(KeyReferenceIdConsts.values()) + .noneMatch((rId) -> rId.name().equals(referenceId)))) { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, eccCurve); + } else { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + } X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias); String certThumbprint = cryptomanagerUtil.getCertificateThumbprintInHex(x509Cert); String uniqueValue = applicationId + KeymanagerConstant.UNDER_SCORE + referenceId + KeymanagerConstant.UNDER_SCORE + @@ -342,17 +353,23 @@ private CertificateInfo getCertificateFromDBStore(String applic String encryptedPrivateKey; alias = UUID.randomUUID().toString(); KeyPair keypair = null; + + CertificateInfo certInfo; if (referenceId.equals(KeyReferenceIdConsts.ED25519_SIGN.name()) && isSignKey) { keypair = keyGenerator.getEd25519KeyPair(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); + } else if (!masterKeyAlgorithm.equals(KeymanagerConstant.RSA)) { + keypair = keyGenerator.getECKeyPair(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); } else { keypair = keyGenerator.getAsymmetricKey(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); } PrivateKey privateKey = keypair.getPrivate(); /** * Will get application's master key information from HSM. On first request for * an applicationId and duration, will create a new keypair. */ - CertificateInfo certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); X509Certificate hsmX509Cert = certInfo.getCertificate(); PublicKey masterPublicKey = hsmX509Cert.getPublicKey(); @@ -670,8 +687,13 @@ private CertificateInfo generateAndStoreAsymmetricKey(String al genAlias = certificateInfo.getAlias(); } return new CertificateInfo<>(genAlias, x509Cert); - } - keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + } + + if (!masterKeyAlgorithm.trim().equals(KeymanagerConstant.RSA)) { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, eccCurve); + } else { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + } x509Cert = (X509Certificate) keyStore.getCertificate(alias); storeAsymmetricKey(alias, applicationId, refId, keyAliasMap, x509Cert, generationDateTime, expiryDateTime); return new CertificateInfo<>(genAlias, x509Cert); @@ -895,7 +917,7 @@ private Object[] getKeyDetails(Optional allowedAppIds; + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String ecCurveName; + /** * KeyGenerator instance to generate asymmetric key pairs */ @@ -177,6 +183,12 @@ public class KeymanagerUtil { @Autowired private CryptoCoreSpec cryptoCore; + @Autowired + private EcCryptoOperation ecCryptoOperation; + + @Autowired + private KeyStore keyStore; + /** * Function to check valid timestamp * @@ -238,10 +250,18 @@ public T setMetaData(T entity) { * @return encrypted key */ public byte[] encryptKey(PrivateKey privateKey, PublicKey masterKey) { - SecretKey symmetricKey = keyGenerator.getSymmetricKey(); - byte[] encryptedPrivateKey = cryptoCore.symmetricEncrypt(symmetricKey, privateKey.getEncoded(), null); - byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(masterKey, symmetricKey.getEncoded()); - return CryptoUtil.combineByteArray(encryptedPrivateKey, encryptedSymmetricKey, keySplitter); + byte[] encryptedSymmetricKey; + byte[] encryptedKey = null; + + if (masterKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA)) { + SecretKey symmetricKey = keyGenerator.getSymmetricKey(); + byte[] encryptedPrivateKey = cryptoCore.symmetricEncrypt(symmetricKey, privateKey.getEncoded(), null); + encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(masterKey, symmetricKey.getEncoded()); + encryptedKey = CryptoUtil.combineByteArray(encryptedPrivateKey, encryptedSymmetricKey, keySplitter); + } else { + encryptedKey = ecCryptoOperation.asymmetricEcEncrypt(masterKey, privateKey.getEncoded(), getEcCurveName(masterKey)); + } + return encryptedKey; } /** @@ -257,16 +277,20 @@ public byte[] decryptKey(byte[] key, PrivateKey privateKey, PublicKey publicKey) public byte[] decryptKey(byte[] key, PrivateKey privateKey, PublicKey publicKey, String keystoreType) { - int keyDemiliterIndex = 0; - final int cipherKeyandDataLength = key.length; - final int keySplitterLength = keySplitter.length(); - keyDemiliterIndex = CryptoUtil.getSplitterIndex(key, keyDemiliterIndex, keySplitter); - byte[] encryptedKey = copyOfRange(key, 0, keyDemiliterIndex); - byte[] encryptedData = copyOfRange(key, keyDemiliterIndex + keySplitterLength, cipherKeyandDataLength); - byte[] decryptedSymmetricKey = cryptoCore.asymmetricDecrypt(privateKey, publicKey, encryptedKey, keystoreType); - SecretKey symmetricKey = new SecretKeySpec(decryptedSymmetricKey, 0, decryptedSymmetricKey.length, - symmetricAlgorithmName); - return cryptoCore.symmetricDecrypt(symmetricKey, encryptedData, null); + if (privateKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA)) { + int keyDemiliterIndex = 0; + final int cipherKeyandDataLength = key.length; + final int keySplitterLength = keySplitter.length(); + keyDemiliterIndex = CryptoUtil.getSplitterIndex(key, keyDemiliterIndex, keySplitter); + byte[] encryptedKey = copyOfRange(key, 0, keyDemiliterIndex); + byte[] encryptedData = copyOfRange(key, keyDemiliterIndex + keySplitterLength, cipherKeyandDataLength); + byte[] decryptedSymmetricKey = cryptoCore.asymmetricDecrypt(privateKey, publicKey, encryptedKey, keystoreType); + SecretKey symmetricKey = new SecretKeySpec(decryptedSymmetricKey, 0, decryptedSymmetricKey.length, + symmetricAlgorithmName); + return cryptoCore.symmetricDecrypt(symmetricKey, encryptedData, null); + } else { + return ecCryptoOperation.asymmetricEcDecrypt(privateKey, key, null, getEcCurveName(publicKey)); + } } /** @@ -451,7 +475,7 @@ public String getCSR(PrivateKey privateKey, PublicKey publicKey, CertificatePara X500Principal csrSubject = new X500Principal("CN=" + certParams.getCommonName() + ", OU=" + certParams.getOrganizationUnit() + ", O=" + certParams.getOrganization() + ", L=" + certParams.getLocation() + ", S=" + certParams.getState() + ", C=" + certParams.getCountry()); - ContentSigner contentSigner = new JcaContentSignerBuilder(getSignatureAlgorithm(keyAlgorithm)).build(privateKey); + ContentSigner contentSigner = new JcaContentSignerBuilder(getSignatureAlgorithm(keyAlgorithm)).setProvider(keyStore.getKeystoreProviderName()).build(privateKey); PKCS10CertificationRequestBuilder pcks10Builder = new JcaPKCS10CertificationRequestBuilder(csrSubject, publicKey); PKCS10CertificationRequest csrObject = pcks10Builder.build(contentSigner); return getPEMFormatedData(csrObject); @@ -511,4 +535,21 @@ public void checkAppIdAllowedForEd25519KeyGen(String applicationId) { KeymanagerErrorConstant.KEY_GEN_NOT_ALLOWED_FOR_APPID.getErrorMessage()); } } + + public String getEcCurveName(PublicKey publicKey) { + SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) subjectPublicKeyInfo.getAlgorithm().getParameters(); + String curveName; + if (KeymanagerConstant.EC_SECP256R1_OID.equals(oid.getId())) { + curveName = ECCurves.SECP256R1.name(); + } else if (KeymanagerConstant.EC_SECP256K1_OID.equals(oid.getId())) { + curveName = ECCurves.SECP256K1.name(); + } else { + throw new io.mosip.kernel.core.exception.NoSuchAlgorithmException( + KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorCode(), + KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorMessage() + ); + } + return curveName; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java index c786c2b2..30841864 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java @@ -22,6 +22,7 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; +import io.mosip.kernel.cryptomanager.service.EcCryptoOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; @@ -88,6 +89,13 @@ public class KeyMigratorServiceImpl implements KeyMigratorService { @Value("${mosip.kernel.zkcrypto.wrap.algorithm-name:AES/ECB/NoPadding}") private String aesECBTransformation; + /** Master Key generation algorithm */ + @Value("${mosip.kernel.keygenerator.asymmetric-algorithm-name:RSA}") + private String keyAlgorithm; + + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String ecCurveName; + /** * KeymanagerDBHelper instance to handle all DB operations */ @@ -118,6 +126,9 @@ public class KeyMigratorServiceImpl implements KeyMigratorService { @Autowired KeyAliasRepository keyAliasRepository; + @Autowired + EcCryptoOperation ecCrypto; + @Override public KeyMigrateBaseKeyResponseDto migrateBaseKey(KeyMigrateBaseKeyRequestDto baseKeyMigrateRequest){ LOGGER.info(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.BASE_KEY, @@ -283,7 +294,12 @@ public ZKKeyMigrateCertficateResponseDto getZKTempCertificate() { LocalDateTime expiryDateTime = localDateTimeStamp.plusDays(1); CertificateParameters certParams = keymanagerUtil.getCertificateParameters(KeyMigratorConstants.ZK_CERT_COMMON_NAME, localDateTimeStamp, expiryDateTime); - keyStore.generateAndStoreAsymmetricKey(alias, null, certParams); + + if (keyAlgorithm.equalsIgnoreCase(KeymanagerConstant.RSA)) { + keyStore.generateAndStoreAsymmetricKey(alias, null, certParams); + } else { + keyStore.generateAndStoreAsymmetricKey(alias, null, certParams, ecCurveName); + } X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias); String certThumbprint = cryptomanagerUtil.getCertificateThumbprintInHex(x509Cert); // Using certThumbprint not generation time because in case more than one migration master key may be @@ -378,18 +394,34 @@ private String getKeyAlias(String keyAppId, String keyRefId, LocalDateTime local } private byte[] encryptRandomKey(byte[] encryptedKeyBytes, Key zkMasterKey, PrivateKey tempPrivateKey, PublicKey tempPublicKey) { - try { - byte[] secretDataBytes = cryptoCore.asymmetricDecrypt(tempPrivateKey, tempPublicKey, encryptedKeyBytes); - Cipher cipher = Cipher.getInstance(aesECBTransformation); - - cipher.init(Cipher.ENCRYPT_MODE, zkMasterKey); - return cipher.doFinal(secretDataBytes, 0, secretDataBytes.length); - } catch(NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException - | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException - | InvalidDataException | io.mosip.kernel.core.crypto.exception.InvalidKeyException e) { - LOGGER.error(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.ZK_KEYS, - KeyMigratorConstants.EMPTY, "Error in encrypting random Key in key migration process.", e); - } + + if (tempPublicKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA)) { + + try { + byte[] secretDataBytes = cryptoCore.asymmetricDecrypt(tempPrivateKey, tempPublicKey, encryptedKeyBytes); + Cipher cipher = Cipher.getInstance(aesECBTransformation); + + cipher.init(Cipher.ENCRYPT_MODE, zkMasterKey); + return cipher.doFinal(secretDataBytes, 0, secretDataBytes.length); + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException + | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException + | InvalidDataException | io.mosip.kernel.core.crypto.exception.InvalidKeyException e) { + LOGGER.error(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.ZK_KEYS, + KeyMigratorConstants.EMPTY, "Error in encrypting random Key in key migration process.", e); + } + } else { + try { + byte[] secreteDataBytes = ecCrypto.asymmetricEcDecrypt(tempPrivateKey, encryptedKeyBytes, null, keymanagerUtil.getEcCurveName(tempPublicKey)); + Cipher cipher = Cipher.getInstance(aesECBTransformation); + cipher.init(Cipher.ENCRYPT_MODE, zkMasterKey); + return cipher.doFinal(secreteDataBytes, 0, secreteDataBytes.length); + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException + | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException + | InvalidDataException | io.mosip.kernel.core.crypto.exception.InvalidKeyException e) { + LOGGER.error(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.ZK_KEYS, + KeyMigratorConstants.EMPTY, "Error in encrypting random Key in key migration process.", e); + } + } return null; } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java index 0c8d9025..e3fc48af 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java @@ -14,14 +14,11 @@ import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import javax.crypto.SecretKey; +import io.mosip.kernel.keymanagerservice.constant.ECCurves; import org.apache.commons.codec.binary.Base64; import org.jose4j.jca.ProviderContext; import org.jose4j.jwa.AlgorithmFactory; @@ -126,6 +123,9 @@ public class SignatureServiceImpl implements SignatureService { @Value("${mosip.kernel.keymanager.jwtsign.enable.secp256k1.algorithm:true}") private boolean enableSecp256k1Algo; + @Value("${mosip.sign-certificate-refid:SIGN}") + private String certificateSignRefID; + /** * Utility to generate Metadata */ @@ -161,11 +161,12 @@ public class SignatureServiceImpl implements SignatureService { private static Map JWT_SIGNATURE_ALGO_IDENT = new HashMap<>(); static { - JWT_SIGNATURE_ALGO_IDENT.put(SignatureConstant.BLANK, AlgorithmIdentifiers.RSA_USING_SHA256); - JWT_SIGNATURE_ALGO_IDENT.put(SignatureConstant.REF_ID_SIGN_CONST, AlgorithmIdentifiers.RSA_USING_SHA256); + JWT_SIGNATURE_ALGO_IDENT.put(KeymanagerConstant.RSA, AlgorithmIdentifiers.RSA_USING_SHA256); JWT_SIGNATURE_ALGO_IDENT.put(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name(), AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256); JWT_SIGNATURE_ALGO_IDENT.put(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name(), AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256); JWT_SIGNATURE_ALGO_IDENT.put(KeyReferenceIdConsts.ED25519_SIGN.name(), AlgorithmIdentifiers.EDDSA); + JWT_SIGNATURE_ALGO_IDENT.put(ECCurves.SECP256R1.name(), AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256); + JWT_SIGNATURE_ALGO_IDENT.put(ECCurves.SECP256K1.name(), AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256); } @PostConstruct @@ -345,8 +346,9 @@ private String sign(String dataToSign, SignatureCertificate certificateResponse, if (includeKeyId && Objects.nonNull(keyId)) jwSign.setKeyIdHeaderValue(keyId); + String algoString = (referenceId.equals(KeymanagerConstant.EMPTY) || referenceId.equals(certificateSignRefID)) ? + SignatureUtil.getJwtSignAlgorithm(x509Certificate) : JWT_SIGNATURE_ALGO_IDENT.get(referenceId); jwSign.setPayload(dataToSign); - String algoString = JWT_SIGNATURE_ALGO_IDENT.get(referenceId); if (!KeyReferenceIdConsts.ED25519_SIGN.name().equals(referenceId)) { ProviderContext provContext = new ProviderContext(); provContext.getSuppliedKeyProviderContext().setSignatureProvider(ecKeyStore.getKeystoreProviderName()); @@ -357,7 +359,7 @@ private String sign(String dataToSign, SignatureCertificate certificateResponse, AlgorithmFactoryFactory.getInstance().getJwsAlgorithmFactory().getSupportedAlgorithms()); LOGGER.info(SignatureConstant.SESSIONID, SignatureConstant.JWT_SIGN, SignatureConstant.BLANK, "Signature Algorithm for the input RefId: " + algoString); - + jwSign.setAlgorithmHeaderValue(algoString); jwSign.setKey(privateKey); jwSign.setDoKeyValidation(false); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java index 238832fe..bbf33b48 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java @@ -5,6 +5,7 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; @@ -24,6 +25,9 @@ import com.nimbusds.jose.util.Base64; import com.nimbusds.jose.util.Base64URL; +import io.mosip.kernel.keymanagerservice.constant.ECCurves; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerErrorConstant; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; @@ -34,6 +38,11 @@ import io.mosip.kernel.core.util.HMACUtils2; import io.mosip.kernel.keymanagerservice.logger.KeymanagerLogger; import io.mosip.kernel.signature.constant.SignatureConstant; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.jose4j.jws.AlgorithmIdentifiers; + +import java.lang.*; /** * Utility class for Signature Service @@ -184,4 +193,26 @@ else return switch (referenceId) { default -> SignatureConstant.JWS_PS256_SIGN_ALGO_CONST; }; } + + public static String getJwtSignAlgorithm(X509Certificate x509Certificate) { + PublicKey publicKey = x509Certificate.getPublicKey(); + String algorithm = publicKey.getAlgorithm(); + + if (KeymanagerConstant.EC_KEY_TYPE.equalsIgnoreCase(algorithm)) { + SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + ASN1ObjectIdentifier curveOid = (ASN1ObjectIdentifier) subjectPublicKeyInfo.getAlgorithm().getParameters(); + + return mapCurveOidToCurveName(curveOid.getId()); + } + return AlgorithmIdentifiers.RSA_USING_SHA256; + } + + private static String mapCurveOidToCurveName(String oid) { + return switch (oid) { + case KeymanagerConstant.EC_SECP256R1_OID -> AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256; + case KeymanagerConstant.EC_SECP256K1_OID -> AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256; + default -> throw new io.mosip.kernel.core.exception.NoSuchAlgorithmException(KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorCode(), + KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorMessage()); + }; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java index aec7adb5..a468c71c 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java @@ -9,6 +9,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.time.LocalDateTime; import java.util.ArrayList; @@ -30,6 +31,9 @@ import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; +import io.mosip.kernel.cryptomanager.service.EcCryptoOperation; +import io.mosip.kernel.keymanager.hsm.util.CertificateUtility; +import io.mosip.kernel.keymanagerservice.repository.KeyAliasRepository; import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -132,6 +136,12 @@ public class ZKCryptoManagerServiceImpl implements ZKCryptoManagerService, Initi @Autowired CryptomanagerUtils cryptomanagerUtil; + @Autowired + EcCryptoOperation ecCryptoCore; + + @Autowired + KeyAliasRepository keyAliasRepository; + @Autowired private CryptoCoreSpec cryptoCore; @@ -392,7 +402,10 @@ private String encryptRandomKey(Key secretRandomKey) { String certificateData = dbKeyStore.get().getCertificateData(); X509Certificate x509Cert = (X509Certificate) keymanagerUtil.convertToCertificate(certificateData); PublicKey publicKey = x509Cert.getPublicKey(); - byte[] encryptedRandomKey = cryptoCore.asymmetricEncrypt(publicKey, secretRandomKey.getEncoded()); + + byte[] encryptedRandomKey = publicKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA) ? cryptoCore.asymmetricEncrypt(publicKey, secretRandomKey.getEncoded()) : + ecCryptoCore.asymmetricEcEncrypt(publicKey, secretRandomKey.getEncoded(), keymanagerUtil.getEcCurveName(publicKey)); + byte[] certThumbprint = cryptomanagerUtil.getCertificateThumbprint(x509Cert); byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedRandomKey); encryptedRandomKeyList.add(CryptoUtil.encodeToURLSafeBase64(concatedData)); @@ -416,29 +429,44 @@ public ReEncryptRandomKeyResponseDto zkReEncryptRandomKey(String encryptedKey){ Map> keyAliasMap = dbHelper.getKeyAliases(pubKeyApplicationId, pubKeyReferenceId, localDateTimeStamp); keyAliases = keyAliasMap.get(KeymanagerConstant.KEYALIAS); } + + String kyAlias = null; String encRandomKey = null; + byte[] encRandomKeyBytes = null; + String certificateThumbprint = null; for (String encKey : encryptedKeyArr) { byte[] encKeyBytes = CryptoUtil.decodeURLSafeBase64(encKey); byte[] certThumbprint = Arrays.copyOfRange(encKeyBytes, 0, CryptomanagerConstant.THUMBPRINT_LENGTH); + encRandomKeyBytes = Arrays.copyOfRange(encKeyBytes, CryptomanagerConstant.THUMBPRINT_LENGTH, encKeyBytes.length); String certThumbprintHex = Hex.toHexString(certThumbprint).toUpperCase(); Optional keyAlias = keyAliases.stream().filter(alias -> alias.getCertThumbprint().equals(certThumbprintHex)) .findFirst(); - + kyAlias = keyAlias.map(KeyAlias::getAlias).orElse(null); + certificateThumbprint = certThumbprintHex; if (!keyAlias.isPresent()) { continue; } encRandomKey = encKey; break; } + + Optional dbKeyStore = keyStoreRepository.findByAlias(kyAlias); + Optional keyAliasObj = keyAliasRepository.findById(Objects.requireNonNull(kyAlias)); + String certificateData = dbKeyStore.get().getCertificateData(); + X509Certificate x509Cert = (X509Certificate) keymanagerUtil.convertToCertificate(certificateData); + if (Objects.isNull(encRandomKey)) { LOGGER.error(ZKCryptoManagerConstants.SESSIONID, ZKCryptoManagerConstants.RE_ENCRYPT_RANDOM_KEY, ZKCryptoManagerConstants.RE_ENCRYPT_RANDOM_KEY, "Thumbprint matching key not found in DB."); throw new ZKCryptoException(ZKCryptoErrorConstants.INVALID_ENCRYPTED_RANDOM_KEY.getErrorCode(), ZKCryptoErrorConstants.INVALID_ENCRYPTED_RANDOM_KEY.getErrorMessage()); } - SymmetricKeyRequestDto symmetricKeyRequestDto = new SymmetricKeyRequestDto( - pubKeyApplicationId, localDateTimeStamp, pubKeyReferenceId, encRandomKey, true); - String randomKey = keyManagerService.decryptSymmetricKey(symmetricKeyRequestDto).getSymmetricKey(); + + PrivateKey privateKey = (PrivateKey) cryptomanagerUtil.getEncryptedPrivateKey(keyAliasObj.get().getApplicationId(), Optional.ofNullable(keyAliasObj.get().getReferenceId()), certificateThumbprint)[0]; + SymmetricKeyRequestDto symmetricKeyRequestDto = new SymmetricKeyRequestDto(pubKeyApplicationId, localDateTimeStamp, pubKeyReferenceId, encRandomKey, true); + + String randomKey = x509Cert.getPublicKey().getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA) ? keyManagerService.decryptSymmetricKey(symmetricKeyRequestDto).getSymmetricKey() : + CryptoUtil.encodeToURLSafeBase64(ecCryptoCore.asymmetricEcDecrypt(privateKey, encRandomKeyBytes, null, keymanagerUtil.getEcCurveName(x509Cert.getPublicKey()))); String encryptedRandomKey = getEncryptedRandomKey(Base64.getEncoder().encodeToString(CryptoUtil.decodeURLSafeBase64(randomKey))); ReEncryptRandomKeyResponseDto responseDto = new ReEncryptRandomKeyResponseDto(); responseDto.setEncryptedKey(encryptedRandomKey); diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/integration/CryptographicServiceIntegrationTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/integration/CryptographicServiceIntegrationTest.java index 3430c10a..66c17296 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/integration/CryptographicServiceIntegrationTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/integration/CryptographicServiceIntegrationTest.java @@ -124,6 +124,7 @@ public void setUp() { requestWithPinWrapper.setId(ID); requestWithPinWrapper.setVersion(VERSION); requestWithPinWrapper.setRequesttime(LocalDateTime.now(ZoneId.of("UTC"))); + when(cryptomanagerUtil.getAlgorithmNameFromHeader(Mockito.any())).thenReturn("RSA"); } @WithUserDetails("reg-processor") @@ -190,7 +191,7 @@ public void testDecrypt() throws Exception { requestDto.setTimeStamp(timeStamp); SymmetricKeyRequestDto symmetricKeyRequestDto = new SymmetricKeyRequestDto(appid, timeStamp, refid, data, true); when(keyManagerService.decryptSymmetricKey(Mockito.any())).thenReturn(symmetricKeyResponseDto); - when(cryptomanagerUtil.parseEncryptKeyHeader(Mockito.any())).thenReturn("".getBytes()); + when(cryptomanagerUtil.parseEncryptKeyHeader(Mockito.any())).thenReturn("RSA".getBytes()); when(cryptomanagerUtil.decodeBase64Data(data)) .thenReturn("MOCKENCRYPTEDKEY#KEY_SPLITTER#MOCKENCRYPTEDDATA".getBytes()); when(cryptomanagerUtil.hasKeyAccess(Mockito.anyString())).thenReturn(true); diff --git a/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java b/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java index 85cb26cf..7688c850 100755 --- a/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java +++ b/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java @@ -21,6 +21,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import io.mosip.kernel.cryptomanager.service.EcCryptoOperation; import jakarta.annotation.PostConstruct; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -163,6 +164,9 @@ public class BaseKeysMigrator { @Autowired CryptomanagerUtils cryptomanagerUtil; + @Autowired + EcCryptoOperation ecCrypto; + @Autowired private CryptoCoreSpec cryptoCore; @@ -249,7 +253,9 @@ private void reEncryptAndUpload(PrivateKeyEntry masterKeyEntry, String masterKey try { byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeBase64(baseKey.getPrivateKey()), masterKey, masterPublicKey); - KeyFactory keyFactory = KeyFactory.getInstance(KeymanagerConstant.RSA); + PublicKey baseKeyPublicKey = keymanagerUtil.convertToCertificate(baseKey.getCertificateData()).getPublicKey(); + + KeyFactory keyFactory = KeyFactory.getInstance(baseKeyPublicKey.getAlgorithm()); PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); String encryptedPrivateKey = CryptoUtil.encodeBase64(keymanagerUtil.encryptKey(privateKey, newKeyMgrPubKey)); Optional keyAliasObj = keyAliasRepository.findById(baseKeyUuid); @@ -353,7 +359,8 @@ private void migrateZKRandomKeys() { int keyIndex = zkKey.getId(); String encryptedKey = zkKey.getKey(); byte[] decryptedZKKey = decryptRandomKey(encryptedKey, zkMasterKey); - byte[] encryptedRandomKey = cryptoCore.asymmetricEncrypt(zkPublicKey, decryptedZKKey); + byte[] encryptedRandomKey = zkPublicKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA) ? cryptoCore.asymmetricEncrypt(zkPublicKey, decryptedZKKey) : + ecCrypto.asymmetricEcEncrypt(zkPublicKey, decryptedZKKey, keymanagerUtil.getEcCurveName(zkPublicKey)); String encodedKey = CryptoUtil.encodeBase64(encryptedRandomKey); ZKKeyDataDto keyDataDto = new ZKKeyDataDto(); keyDataDto.setKeyIndex(keyIndex);