Reputation: 842
I'm trying to implement this OpenSSL hybrid wrapping using SunJCE provider and unwrap the key to AWS HSM, unfortunately failing miserably so far.
Command: unWrapKey -f wrapped_key_material -w 2883603 -noheader -l test -kc 3 -kt 0 -m 7
Cfm3CreateUnwrapTemplate2 returned: 0x00 : HSM Return: SUCCESS
Cfm2UnWrapWithTemplate2 returned: 0xad
HSM Error: Operation Failed. Invalid inputs passed
I'm assuming OpenSSL id-aes256-wrap-pad
cipher corresponds to AES/CBC/PKCS5Padding
in WRAP_MODE
From OpenSSL doc:
aes-[128|192|256]-wrap-pad key wrapping with padding using 128/192/256 bit AES
This is what I have so far:
// Generate 256bit AES KEK
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey masterKey = keyGen.generateKey();
// Load public RSA key
byte[] publicKeyBytes = Files.readAllBytes(Paths.get(publicKeyFile));
String publicPem = new String(publicKeyBytes, "ASCII");
publicPem = publicPem.replaceAll("^-----BEGIN .* KEY-----\n", "");
publicPem = publicPem.replaceAll("-----END .* KEY-----$", "");
byte[] encoded = Base64.getMimeDecoder().decode(publicPem);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encoded));
// Load private RSA pkcs#8 der
byte[] privateKeyBytes = Files.readAllBytes(Paths.get(privateKeyFile));
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
// Set RSA cipher parameters
OAEPParameterSpec spec = new OAEPParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
Cipher oaep = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1ANDMGF1Padding", "SunJCE");
oaep.init(Cipher.WRAP_MODE, publicKey, spec);
// Set AES cipher parameters
byte[] ivBytes = {
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6,
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6,
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6,
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6,
};
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
aes.init(Cipher.WRAP_MODE, masterKey, ivSpec);
// Wrap private key with AES KEK
byte[] wrappedPrivateKey = aes.wrap(privateKey);
// Wrap AES KEK with public RSA key
byte[] wrappedMasterKey;
try {
wrappedMasterKey = oaep.wrap(masterKey);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(
"AES key should always fit OAEP with normal sized RSA key", e);
}
// Concatenate wrapped KEK and wrapped private key
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(wrappedMasterKey);
outputStream.write(wrappedPrivateKey);
byte wrappedKeys[] = outputStream.toByteArray();
Files.write(new File("wrapped_key_material").toPath(), wrappedKeys);
My uncertainties are mainly with my initialization vector, they pass hex A65959A6 to OpenSSL
for (byte b : iv) {
String st = String.format("%02X", b);
System.out.print(st);
}
My IV is A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6A6
AWS HSM consider 0xa6a6a6a6a6a6a6a6
as default IV
Not sure if my concatenation is done correctly too.
Upvotes: 1
Views: 311
Reputation: 842
CBC is not the right one, my IV is wrong too.
Correct cipher is AESWrapPad
introduced in Java 17 and IV should be {(byte)0xa6, (byte)0x59, (byte)0x59, (byte)0xa6}
now i can import to AWS HSM.
Maven support for Java 17 starts from 3.8.x
Upvotes: 1