197 lines
8.1 KiB
Java
197 lines
8.1 KiB
Java
package com.eactive.eai.common.hsm;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.File;
|
|
import java.io.InputStream;
|
|
import java.lang.reflect.Method;
|
|
import java.nio.file.Files;
|
|
import java.security.KeyStore;
|
|
import java.security.KeyStoreException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.Provider;
|
|
import java.security.Security;
|
|
import java.security.UnrecoverableKeyException;
|
|
import java.security.spec.InvalidKeySpecException;
|
|
import java.util.Base64;
|
|
|
|
import javax.crypto.SecretKey;
|
|
import javax.crypto.SecretKeyFactory;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
public class HsmAddKeyTest {
|
|
|
|
/**
|
|
* JDK 버전에 따라 SunPKCS11 Provider 를 생성한다.
|
|
*
|
|
* JDK 8 : SunPKCS11(InputStream) 생성자를 리플렉션으로 호출 JDK 9+:
|
|
* Provider.configure(configFilePath) 를 리플렉션으로 호출
|
|
*
|
|
* 두 경로 모두 리플렉션을 사용하므로 컴파일 타임에 JDK 버전 의존성이 없다.
|
|
*/
|
|
static Provider createProvider(String cfgContent) throws Exception {
|
|
String javaVersion = System.getProperty("java.version");
|
|
if (javaVersion.startsWith("1.")) {
|
|
// JDK 8: new SunPKCS11(InputStream)
|
|
InputStream is = new ByteArrayInputStream(cfgContent.getBytes("UTF-8"));
|
|
return (Provider) Class.forName("sun.security.pkcs11.SunPKCS11").getConstructor(InputStream.class)
|
|
.newInstance(is);
|
|
} else {
|
|
// JDK 9+: Security.getProvider("SunPKCS11").configure(configFilePath)
|
|
// configure() 는 JDK 9 에서 추가된 메서드이므로 리플렉션으로 호출
|
|
File tmp = File.createTempFile("pkcs11-hsm-", ".cfg");
|
|
tmp.deleteOnExit();
|
|
Files.write(tmp.toPath(), cfgContent.getBytes("UTF-8"));
|
|
Provider base = Security.getProvider("SunPKCS11");
|
|
Method configure = Provider.class.getMethod("configure", String.class);
|
|
return (Provider) configure.invoke(base, tmp.getAbsolutePath());
|
|
}
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
// String config = "name = ProtectServer\r\n"
|
|
// + "library = /usr/safenet/protecttoolkit5/ptk/lib/libcryptoki.so\r\n"
|
|
// + "slot = 0";
|
|
|
|
// String config = "name = SoftHSM\r\nlibrary = C:/SoftHSM2/lib/softhsm2-x64.dll\r\nslotListIndex = 0\r\n";
|
|
|
|
String config = "name = SoftHSM\r\n"
|
|
+ "library = C:/SoftHSM2/lib/softhsm2-x64.dll\r\n"
|
|
+ "slotListIndex = 0\r\n"
|
|
+ "attributes(*, CKO_SECRET_KEY, CKK_AES) = {\r\n"
|
|
+ " CKA_TOKEN = true\r\n"
|
|
+ " CKA_SENSITIVE = false\r\n"
|
|
+ " CKA_EXTRACTABLE = true\r\n"
|
|
+ " CKA_ENCRYPT = true\r\n"
|
|
+ " CKA_DECRYPT = true\r\n"
|
|
+ "}\r\n";
|
|
|
|
KeyStore keyStore;
|
|
// Provider pkcs11Provider = HsmManagerSingleTest.createProvider(config);
|
|
InputStream is = new ByteArrayInputStream(config.getBytes("UTF-8"));
|
|
Provider pkcs11Provider = (Provider) Class.forName("sun.security.pkcs11.SunPKCS11")
|
|
.getConstructor(InputStream.class).newInstance(is);
|
|
Security.addProvider(pkcs11Provider);
|
|
String pin = "1234";
|
|
keyStore = KeyStore.getInstance("PKCS11", pkcs11Provider);
|
|
|
|
char[] pinChars = (pin != null) ? pin.toCharArray() : null;
|
|
keyStore.load(null, pinChars);
|
|
|
|
// addKey("20250916_openapi_erpbank_t", "55187afc5d36a2e3b71f3bf992947389964ac5ea0bc8ebe2297265134fa34cb9",
|
|
// keyStore, pkcs11Provider);
|
|
// addKey("20240401_openapi_kakaobank_t", "f009328cb94f5c866ff730735ce8031b43ca84f9266ced641b4046c6a5c21038",
|
|
// keyStore, pkcs11Provider);
|
|
// addKey("20250620_openapi_coocon_t", "3e7a7673392c424e58265c7b6f2e596f7a59542b277472704c3d5d6c70226673",
|
|
// keyStore, pkcs11Provider);
|
|
// addKey("20211221_openapi_kakaopay_t", "23667b665037785c3c312a414b6c566d2f3832476b254646727c4d703d484534",
|
|
// keyStore, pkcs11Provider);
|
|
//
|
|
// addKey("20250916_openapi_erpbank_t_0", "55187afc5d36a2e3b71f3bf992947389964ac5ea0bc8ebe2297265134fa34cb9",
|
|
// keyStore, pkcs11Provider);
|
|
// addKey("20240401_openapi_kakaobank_t_0", "f009328cb94f5c866ff730735ce8031b43ca84f9266ced641b4046c6a5c21038",
|
|
// keyStore, pkcs11Provider);
|
|
// addKey("20250620_openapi_coocon_t_0", "3e7a7673392c424e58265c7b6f2e596f7a59542b277472704c3d5d6c70226673",
|
|
// keyStore, pkcs11Provider);
|
|
// addKey("20211221_openapi_kakaopay_t_0", "23667b665037785c3c312a414b6c566d2f3832476b254646727c4d703d484534",
|
|
// keyStore, pkcs11Provider);
|
|
|
|
addKey("20260518_openapi_npayloan_t", "7f7f6608a0c2f28d9a7e53f81b265f12b46f893ffcecc253bdc0561338e10208",
|
|
keyStore, pkcs11Provider);
|
|
addKey("20260518_openapi_npayloan_iv_t", "b797008af20f0e1eda6c71d14bec5bb7",
|
|
keyStore, pkcs11Provider);
|
|
addKey("20241022_openapi_toss_t", "3051557a6c786475536c4f532f4c6b6b436a4c312f42434947764d336b66306e",
|
|
keyStore, pkcs11Provider);
|
|
addKey("20250307_openapi_tossbank_t", "48b8465313d6fc529a9f16c3347cde55a663efaf9ade41429c1cb484398bcf93",
|
|
keyStore, pkcs11Provider);
|
|
addKey("20250307_openapi_tossbank_iv_t", "2bdf93b1f872962d2aa2f890e179e3e0",
|
|
keyStore, pkcs11Provider);
|
|
addKey("20240524_openapi_banksalad_t", "466166733957513862616a646e55686a353759554c784e4a6463783279767035",
|
|
keyStore, pkcs11Provider);
|
|
|
|
System.out.println("HsmManager] 초기화 완료. Provider=" + pkcs11Provider.getName());
|
|
|
|
java.util.Enumeration<String> aliases = keyStore.aliases();
|
|
StringBuilder aliasList = new StringBuilder();
|
|
while (aliases.hasMoreElements()) {
|
|
if (aliasList.length() > 0)
|
|
aliasList.append(", ");
|
|
|
|
String alias = aliases.nextElement();
|
|
aliasList.append(alias);
|
|
|
|
java.security.Key key = keyStore.getKey(alias, null);
|
|
if (key instanceof SecretKey) {
|
|
SecretKey secretKey = (SecretKey) key;
|
|
if (secretKey.getEncoded() != null) {
|
|
String encBase64 = Base64.getEncoder().encodeToString(secretKey.getEncoded());
|
|
System.out.println("HsmManager] HSM - alias:" + alias + ", base64:" + encBase64 + ", secretKey:" + secretKey);
|
|
} else {
|
|
System.out
|
|
.println("HsmManager] HSM - secretKey null - alias:" + alias + ", secretKey:" + secretKey);
|
|
}
|
|
}
|
|
}
|
|
System.out.println("HsmManager] HSM 키 목록: [" + aliasList + "]");
|
|
}
|
|
|
|
private static void addKey(String keyAlias, String keyValue, KeyStore keyStore, Provider pkcs11Provider)
|
|
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, InvalidKeySpecException {
|
|
byte[] keyBytes = hexToBytes(keyValue);
|
|
|
|
SecretKeySpec spec = new SecretKeySpec(keyBytes, "AES");
|
|
SecretKeyFactory factory = SecretKeyFactory.getInstance("AES", pkcs11Provider);
|
|
SecretKey fixedKey = (SecretKey) factory.generateSecret(spec);
|
|
|
|
// SecretKey fixedKey = new SecretKeySpec(keyBytes, "AES");
|
|
|
|
keyStore.setKeyEntry(keyAlias, fixedKey, null, null);
|
|
|
|
// // 2. wrapping key 생성 (최초 1회만 — 이후엔 재사용)
|
|
// KeyGenerator wrapKeyGen = KeyGenerator.getInstance("AES", pkcs11Provider);
|
|
// wrapKeyGen.init(256);
|
|
// SecretKey wrappingKey = wrapKeyGen.generateKey();
|
|
//
|
|
// // 3. 테스트 환경 key 값 지정
|
|
// byte[] testKeyBytes = hexToBytes(keyValue);
|
|
// SecretKey targetKeySpec = new SecretKeySpec(testKeyBytes, "AES");
|
|
//
|
|
// // 4. wrap
|
|
// Cipher wrapCipher = Cipher.getInstance("AESWRAP", pkcs11Provider);
|
|
// wrapCipher.init(Cipher.WRAP_MODE, wrappingKey);
|
|
// byte[] wrapped = wrapCipher.wrap(targetKeySpec);
|
|
//
|
|
// // 5. unwrap → SoftHSM2 내부에 실제 등록
|
|
// Cipher unwrapCipher = Cipher.getInstance("AESWRAP", pkcs11Provider);
|
|
// unwrapCipher.init(Cipher.UNWRAP_MODE, wrappingKey);
|
|
// SecretKey hsmKey = (SecretKey) unwrapCipher.unwrap(wrapped, "AES", Cipher.SECRET_KEY
|
|
//
|
|
// );
|
|
//
|
|
// // 6. 평문 byte 배열 즉시 제거
|
|
// Arrays.fill(testKeyBytes, (byte) 0);
|
|
//
|
|
// System.out.println("Key 등록 완료: " + hsmKey.getAlgorithm() + " / " + hsmKey.getFormat());
|
|
//
|
|
// // 7. 등록 확인 — alias 지정해서 KeyStore에 올리고 싶으면:
|
|
// keyStore.setKeyEntry(keyAlias, hsmKey, null, null);
|
|
}
|
|
|
|
private static byte[] hexToBytes(String hex) {
|
|
int len = hex.length();
|
|
byte[] data = new byte[len / 2];
|
|
for (int i = 0; i < len; i += 2) {
|
|
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static String bytesToHex(byte[] bytes) {
|
|
StringBuilder sb = new StringBuilder();
|
|
for (byte b : bytes) {
|
|
sb.append(String.format("%02X", b));
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
}
|