Filip Stefanov
Filip Stefanov

Reputation: 842

RFC 5649 Key wrapping with SunJCE provider

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

Answers (1)

Filip Stefanov
Filip Stefanov

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

Related Questions