Search code examples
javacryptographyjose4jjwe

What is the algorithm string for 'AGCM256-KW' in java cryptography, to be used in Cipher.getInstance(String algo)?


referring this, I have to encrypt using algorithm AGCM256-­KW. I am using Java Cryptography and I didn't find any such algorithm. Closest I found was AES_256/GCM/NoPadding but it has no KW (Key wrapping).

here is my test code

    public void testEncryption(String algo) {
    String shared_secret = "LyQnklSrxsk3Ch2+AHi9HoDW@//x1LwM123QP/ln";
    try {

        // Step 1 - Create SHA-256 digest of the shared key
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(shared_secret.getBytes("UTF-8"));

        // Step 2 - generate a 256 bit Content Encryption Key(CEK)
        KeyGenerator kg = KeyGenerator.getInstance("AES");
        kg.init(256);
        SecretKey cek = kg.generateKey();

        // Step 3 - encrypt the CEK using 256 bit digest generated in Step 1
        // and 96 bit random IV. Algorithm should be

        // random 96 bit Initialize Vector
        SecureRandom random = new SecureRandom();
        // byte iv[] = new byte[96];
        // random.nextBytes(iv);
        byte iv[] = random.generateSeed(96);
        System.out.println("IV: " + toBase64(iv) + " length: " + iv.length);
        IvParameterSpec ivspec = new IvParameterSpec(iv);
        GCMParameterSpec gspec = new GCMParameterSpec(96, iv);

        // encrypt
        Cipher cipher = Cipher.getInstance(algo);
        System.out.println(String.format("CEK Cipher alg:%S provider:%S", cipher.getAlgorithm(),
                cipher.getProvider().getName()));

        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(digest, "AES"), gspec);
        byte[] result = cipher.doFinal(cek.getEncoded());

        System.out.println(String.format("Encrypted CEK :%S", toBase64(result)));

    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Update 1 I think I can use jose4j library which has APIs for JWE.


Solution

  • Yes, the Visa Token Services appear to be using JWE (now RFC 7516) so you can use jose4j for this. Here's some sample code that shows encrypting and decrypting some content with JWE using A256GCMKW and AGCM256:

        // shared secret hashed to key from your example
        String shared_secret = "LyQnklSrxsk3Ch2+AHi9HoDW@//x1LwM123QP/ln";
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(shared_secret.getBytes("UTF-8"));
    
        JsonWebEncryption jwe = new JsonWebEncryption();
    
        // A256GCMKW for key wrap
        jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.A256GCMKW);
    
        // A256GCM for content encryption
        jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_256_GCM);
    
        // the key (from above)
        jwe.setKey(new SecretKeySpec(digest, "AES"));
    
        // whatever content you want to encrypt
        jwe.setPayload("some important content to be encrypted and integrity protected");
    
        // Produce the JWE compact serialization, which is where the actual encryption is done.
        // The JWE compact serialization consists of five base64url encoded parts
        // combined with a dot ('.') character in the general format of
        // <header>.<encrypted key>.<initialization vector>.<ciphertext>.<authentication tag>
        String serializedJwe = jwe.getCompactSerialization();
    
    
        // Do something with the JWE. Like send it to some other party over the clouds
        // and through the interwebs.
        System.out.println("JWE compact serialization: " + serializedJwe);
    
        // That other party, the receiver, can then use JsonWebEncryption to decrypt the message.
        JsonWebEncryption receiverJwe = new JsonWebEncryption();
    
        // Set the compact serialization on new Json Web Encryption object
        receiverJwe.setCompactSerialization(serializedJwe);
    
        // Symmetric encryption, like we are doing here, requires that both parties have the same key.
        // The key will have had to have been securely exchanged out-of-band somehow.
        receiverJwe.setKey(new SecretKeySpec(digest, "AES"));
    
        // Get the message that was encrypted in the JWE. This step performs the actual decryption steps.
        String plaintext = receiverJwe.getPlaintextString();
    
        // And do whatever you need to do with the clear text message.
        System.out.println("plaintext: " + plaintext);