@Test public void decryptWithTestVectors() throws GeneralSecurityException { for (RsaKemHybridTestVector vector : rsaKemHybridTestVectors) { String hmacAlgo = vector.hmacAlgo; byte[] salt = vector.salt; RSAPrivateKey rsaPrivateKey = vector.privateKey; HybridDecrypt hybridDecrypt = new RsaKemHybridDecrypt( rsaPrivateKey, hmacAlgo, salt, new AesGcmFactory(vector.aesGcmKeySizeInBytes)); byte[] plaintext = hybridDecrypt.decrypt(vector.ciphertext, vector.contextInfo); assertThat(Hex.encode(plaintext)).isEqualTo(vector.plaintext); } }
@Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException { int modSizeInBytes = RsaKem.bigIntSizeInBytes(recipientPrivateKey.getModulus()); if (ciphertext.length < modSizeInBytes) { throw new GeneralSecurityException( String.format( "Ciphertext must be of at least size %d bytes, but got %d", modSizeInBytes, ciphertext.length)); } ByteBuffer cipherBuffer = ByteBuffer.wrap(ciphertext); byte[] token = new byte[modSizeInBytes]; cipherBuffer.get(token); Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding"); rsaCipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey); byte[] sharedSecret = rsaCipher.doFinal(token); byte[] demKey = Hkdf.computeHkdf( hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes()); Aead aead = aeadFactory.createAead(demKey); byte[] demPayload = new byte[cipherBuffer.remaining()]; cipherBuffer.get(demPayload); return aead.decrypt(demPayload, RsaKem.EMPTY_AAD); }
RsaKemHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException { int modSizeInBytes = RsaKem.bigIntSizeInBytes(recipientPrivateKey.getModulus()); if (ciphertext.length < modSizeInBytes) { throw new GeneralSecurityException( String.format( "Ciphertext must be of at least size %d bytes, but got %d", modSizeInBytes, ciphertext.length)); } ByteBuffer cipherBuffer = ByteBuffer.wrap(ciphertext); byte[] token = new byte[modSizeInBytes]; cipherBuffer.get(token); Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding"); rsaCipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey); byte[] sharedSecret = rsaCipher.doFinal(token); byte[] demKey = Hkdf.computeHkdf( hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes()); Aead aead = aeadFactory.createAead(demKey); byte[] demPayload = new byte[cipherBuffer.remaining()]; cipherBuffer.get(demPayload); return aead.decrypt(demPayload, RsaKem.EMPTY_AAD); } }
RsaKemHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException { int modSizeInBytes = RsaKem.bigIntSizeInBytes(recipientPrivateKey.getModulus()); if (ciphertext.length < modSizeInBytes) { throw new GeneralSecurityException( String.format( "Ciphertext must be of at least size %d bytes, but got %d", modSizeInBytes, ciphertext.length)); } ByteBuffer cipherBuffer = ByteBuffer.wrap(ciphertext); byte[] token = new byte[modSizeInBytes]; cipherBuffer.get(token); Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding"); rsaCipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey); byte[] sharedSecret = rsaCipher.doFinal(token); byte[] demKey = Hkdf.computeHkdf( hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes()); Aead aead = aeadFactory.createAead(demKey); byte[] demPayload = new byte[cipherBuffer.remaining()]; cipherBuffer.get(demPayload); return aead.decrypt(demPayload, RsaKem.EMPTY_AAD); } RsaKemHybridDecrypt(
      final RSAPrivateKey recipientPrivateKey,
      String hkdfHmacAlgo,
      final byte[] hkdfSalt,
      AeadFactory aeadFactory); }
RsaKemHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException { int modSizeInBytes = RsaKem.bigIntSizeInBytes(recipientPrivateKey.getModulus()); if (ciphertext.length < modSizeInBytes) { throw new GeneralSecurityException( String.format( "Ciphertext must be of at least size %d bytes, but got %d", modSizeInBytes, ciphertext.length)); } ByteBuffer cipherBuffer = ByteBuffer.wrap(ciphertext); byte[] token = new byte[modSizeInBytes]; cipherBuffer.get(token); Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding"); rsaCipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey); byte[] sharedSecret = rsaCipher.doFinal(token); byte[] demKey = Hkdf.computeHkdf( hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes()); Aead aead = aeadFactory.createAead(demKey); byte[] demPayload = new byte[cipherBuffer.remaining()]; cipherBuffer.get(demPayload); return aead.decrypt(demPayload, RsaKem.EMPTY_AAD); } RsaKemHybridDecrypt(
      final RSAPrivateKey recipientPrivateKey,
      String hkdfHmacAlgo,
      final byte[] hkdfSalt,
      AeadFactory aeadFactory); @Override byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo); }
RsaKemHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo) throws GeneralSecurityException { int modSizeInBytes = RsaKem.bigIntSizeInBytes(recipientPrivateKey.getModulus()); if (ciphertext.length < modSizeInBytes) { throw new GeneralSecurityException( String.format( "Ciphertext must be of at least size %d bytes, but got %d", modSizeInBytes, ciphertext.length)); } ByteBuffer cipherBuffer = ByteBuffer.wrap(ciphertext); byte[] token = new byte[modSizeInBytes]; cipherBuffer.get(token); Cipher rsaCipher = Cipher.getInstance("RSA/ECB/NoPadding"); rsaCipher.init(Cipher.DECRYPT_MODE, recipientPrivateKey); byte[] sharedSecret = rsaCipher.doFinal(token); byte[] demKey = Hkdf.computeHkdf( hkdfHmacAlgo, sharedSecret, hkdfSalt, contextInfo, aeadFactory.getKeySizeInBytes()); Aead aead = aeadFactory.createAead(demKey); byte[] demPayload = new byte[cipherBuffer.remaining()]; cipherBuffer.get(demPayload); return aead.decrypt(demPayload, RsaKem.EMPTY_AAD); } RsaKemHybridDecrypt(
      final RSAPrivateKey recipientPrivateKey,
      String hkdfHmacAlgo,
      final byte[] hkdfSalt,
      AeadFactory aeadFactory); @Override byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo);  }