package org.jboss.resteasy.jose.jwe.crypto; import org.jboss.resteasy.jose.Base64Url; import org.jboss.resteasy.jose.i18n.Messages; import org.jboss.resteasy.jose.jwe.Algorithm; import org.jboss.resteasy.jose.jwe.CompressionAlgorithm; import org.jboss.resteasy.jose.jwe.EncryptionMethod; import javax.crypto.SecretKey; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; /** * Direct encrypter with a * shared symmetric key. This class is thread-safe. * <p/> * <p>Supports the following JWE algorithms: * <p/> * <ul> * <li>DIR * </ul> * <p/> * <p>Supports the following encryption methods: * <p/> * <ul> * <li>A128CBC_HS256} * <li>A256CBC_HS512} * <li>A128GCM} * <li>A256GCM} * </ul> * * @author Vladimir Dzhuvinov * @version $version$ (2013-05-29) */ public class DirectEncrypter { /** * Random byte generator. */ private static SecureRandom randomGen; /** * Initialises the secure random byte generator. * * @throws RuntimeException If the secure random byte generator couldn't * be instantiated. */ private static void initSecureRandom() { try { randomGen = SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e.getMessage(), e); } } public static String encrypt(EncryptionMethod enc, CompressionAlgorithm compressionAlgorithm, String encodedJWEHeader, final SecretKey key, final byte[] bytes) { if (randomGen == null) initSecureRandom(); if (enc.getCekBitLength() != key.getEncoded().length * 8) { throw new RuntimeException(Messages.MESSAGES.contentEncryptionKeyLength(enc.getCekBitLength(), enc)); } // Apply compression if instructed byte[] plainText = DeflateHelper.applyCompression(compressionAlgorithm, bytes); // Compose the AAD byte[] aad = encodedJWEHeader.getBytes(StandardCharsets.UTF_8); // Encrypt the plain text according to the JWE enc byte[] iv; AuthenticatedCipherText authCipherText; if (enc.equals(EncryptionMethod.A128CBC_HS256) || enc.equals(EncryptionMethod.A256CBC_HS512)) { iv = AESCBC.generateIV(randomGen); authCipherText = AESCBC.encryptAuthenticated(key, iv, plainText, aad); } else if (enc.equals(EncryptionMethod.A128GCM) || enc.equals(EncryptionMethod.A256GCM)) { iv = AESGCM.generateIV(randomGen); authCipherText = AESGCM.encrypt(key, iv, plainText, aad); } else { throw new RuntimeException(Messages.MESSAGES.unsupportedEncryptionMethod()); } StringBuilder builder = new StringBuilder(encodedJWEHeader) .append('.') .append('.').append(Base64Url.encode(iv)) .append('.').append(Base64Url.encode(authCipherText.getCipherText())) .append('.').append(Base64Url.encode(authCipherText.getAuthenticationTag())); return builder.toString(); } }