@Test public void testEncryptDecryptWithInvalidRecordSizes() throws Exception { KeyPair uaKeyPair = EllipticCurves.generateKeyPair(WebPushConstants.NIST_P256_CURVE_TYPE); ECPrivateKey uaPrivateKey = (ECPrivateKey) uaKeyPair.getPrivate(); ECPublicKey uaPublicKey = (ECPublicKey) uaKeyPair.getPublic(); byte[] authSecret = Random.randBytes(16); { try { new WebPushHybridDecrypt.Builder() .withRecordSize(WebPushConstants.MAX_CIPHERTEXT_SIZE + 1) .withAuthSecret(authSecret) .withRecipientPublicKey(uaPublicKey) .withRecipientPrivateKey(uaPrivateKey) .build(); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException ex) { } try { new WebPushHybridDecrypt.Builder() .withRecordSize(WebPushConstants.CIPHERTEXT_OVERHEAD - 1) .withAuthSecret(authSecret) .withRecipientPublicKey(uaPublicKey) .withRecipientPrivateKey(uaPrivateKey) .build(); } catch (IllegalArgumentException ex) { } } { for (int i = 0; i < 50; i++) { int recordSize = WebPushConstants.CIPHERTEXT_OVERHEAD + Random.randInt( WebPushConstants.MAX_CIPHERTEXT_SIZE - WebPushConstants.CIPHERTEXT_OVERHEAD - 1); HybridEncrypt hybridEncrypt = new WebPushHybridEncrypt.Builder() .withRecordSize(recordSize) .withAuthSecret(authSecret) .withRecipientPublicKey(uaPublicKey) .build(); HybridDecrypt hybridDecrypt = new WebPushHybridDecrypt.Builder() .withRecordSize(recordSize + 1) .withAuthSecret(authSecret) .withRecipientPublicKey(uaPublicKey) .withRecipientPrivateKey(uaPrivateKey) .build(); byte[] plaintext = Random.randBytes(recordSize - WebPushConstants.CIPHERTEXT_OVERHEAD); byte[] ciphertext = hybridEncrypt.encrypt(plaintext, null ); try { hybridDecrypt.decrypt(ciphertext, null ); fail("Expected GeneralSecurityException"); } catch (GeneralSecurityException ex) { } } } }
@Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo ) throws GeneralSecurityException { if (contextInfo != null) { throw new GeneralSecurityException("contextInfo must be null because it is unused"); } if (ciphertext.length < WebPushConstants.CIPHERTEXT_OVERHEAD) { throw new GeneralSecurityException("ciphertext too short"); } if (ciphertext.length > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("ciphertext too long"); } ByteBuffer record = ByteBuffer.wrap(ciphertext); byte[] salt = new byte[WebPushConstants.SALT_SIZE]; record.get(salt); int recordSize = record.getInt(); if (recordSize != this.recordSize || recordSize < ciphertext.length || recordSize > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("invalid record size: " + recordSize); } int publicKeySize = (int) record.get(); if (publicKeySize != WebPushConstants.PUBLIC_KEY_SIZE) { throw new GeneralSecurityException("invalid ephemeral public key size: " + publicKeySize); } byte[] asPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE]; record.get(asPublicKey); ECPoint asPublicPoint = EllipticCurves.pointDecode( WebPushConstants.NIST_P256_CURVE_TYPE, WebPushConstants.UNCOMPRESSED_POINT_FORMAT, asPublicKey); byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE]; record.get(payload); byte[] ecdhSecret = EllipticCurves.computeSharedSecret(recipientPrivateKey, asPublicPoint); byte[] ikm = WebPushUtil.computeIkm(ecdhSecret, authSecret, recipientPublicKey, asPublicKey); byte[] cek = WebPushUtil.computeCek(ikm, salt); byte[] nonce = WebPushUtil.computeNonce(ikm, salt); return decrypt(cek, nonce, payload); }
WebPushHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo ) throws GeneralSecurityException { if (contextInfo != null) { throw new GeneralSecurityException("contextInfo must be null because it is unused"); } if (ciphertext.length < WebPushConstants.CIPHERTEXT_OVERHEAD) { throw new GeneralSecurityException("ciphertext too short"); } if (ciphertext.length > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("ciphertext too long"); } ByteBuffer record = ByteBuffer.wrap(ciphertext); byte[] salt = new byte[WebPushConstants.SALT_SIZE]; record.get(salt); int recordSize = record.getInt(); if (recordSize != this.recordSize || recordSize < ciphertext.length || recordSize > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("invalid record size: " + recordSize); } int publicKeySize = (int) record.get(); if (publicKeySize != WebPushConstants.PUBLIC_KEY_SIZE) { throw new GeneralSecurityException("invalid ephemeral public key size: " + publicKeySize); } byte[] asPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE]; record.get(asPublicKey); ECPoint asPublicPoint = EllipticCurves.pointDecode( WebPushConstants.NIST_P256_CURVE_TYPE, WebPushConstants.UNCOMPRESSED_POINT_FORMAT, asPublicKey); byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE]; record.get(payload); byte[] ecdhSecret = EllipticCurves.computeSharedSecret(recipientPrivateKey, asPublicPoint); byte[] ikm = WebPushUtil.computeIkm(ecdhSecret, authSecret, recipientPublicKey, asPublicKey); byte[] cek = WebPushUtil.computeCek(ikm, salt); byte[] nonce = WebPushUtil.computeNonce(ikm, salt); return decrypt(cek, nonce, payload); } }
WebPushHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo ) throws GeneralSecurityException { if (contextInfo != null) { throw new GeneralSecurityException("contextInfo must be null because it is unused"); } if (ciphertext.length < WebPushConstants.CIPHERTEXT_OVERHEAD) { throw new GeneralSecurityException("ciphertext too short"); } if (ciphertext.length > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("ciphertext too long"); } ByteBuffer record = ByteBuffer.wrap(ciphertext); byte[] salt = new byte[WebPushConstants.SALT_SIZE]; record.get(salt); int recordSize = record.getInt(); if (recordSize != this.recordSize || recordSize < ciphertext.length || recordSize > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("invalid record size: " + recordSize); } int publicKeySize = (int) record.get(); if (publicKeySize != WebPushConstants.PUBLIC_KEY_SIZE) { throw new GeneralSecurityException("invalid ephemeral public key size: " + publicKeySize); } byte[] asPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE]; record.get(asPublicKey); ECPoint asPublicPoint = EllipticCurves.pointDecode( WebPushConstants.NIST_P256_CURVE_TYPE, WebPushConstants.UNCOMPRESSED_POINT_FORMAT, asPublicKey); byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE]; record.get(payload); byte[] ecdhSecret = EllipticCurves.computeSharedSecret(recipientPrivateKey, asPublicPoint); byte[] ikm = WebPushUtil.computeIkm(ecdhSecret, authSecret, recipientPublicKey, asPublicKey); byte[] cek = WebPushUtil.computeCek(ikm, salt); byte[] nonce = WebPushUtil.computeNonce(ikm, salt); return decrypt(cek, nonce, payload); } private  WebPushHybridDecrypt(Builder builder); }
WebPushHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo ) throws GeneralSecurityException { if (contextInfo != null) { throw new GeneralSecurityException("contextInfo must be null because it is unused"); } if (ciphertext.length < WebPushConstants.CIPHERTEXT_OVERHEAD) { throw new GeneralSecurityException("ciphertext too short"); } if (ciphertext.length > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("ciphertext too long"); } ByteBuffer record = ByteBuffer.wrap(ciphertext); byte[] salt = new byte[WebPushConstants.SALT_SIZE]; record.get(salt); int recordSize = record.getInt(); if (recordSize != this.recordSize || recordSize < ciphertext.length || recordSize > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("invalid record size: " + recordSize); } int publicKeySize = (int) record.get(); if (publicKeySize != WebPushConstants.PUBLIC_KEY_SIZE) { throw new GeneralSecurityException("invalid ephemeral public key size: " + publicKeySize); } byte[] asPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE]; record.get(asPublicKey); ECPoint asPublicPoint = EllipticCurves.pointDecode( WebPushConstants.NIST_P256_CURVE_TYPE, WebPushConstants.UNCOMPRESSED_POINT_FORMAT, asPublicKey); byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE]; record.get(payload); byte[] ecdhSecret = EllipticCurves.computeSharedSecret(recipientPrivateKey, asPublicPoint); byte[] ikm = WebPushUtil.computeIkm(ecdhSecret, authSecret, recipientPublicKey, asPublicKey); byte[] cek = WebPushUtil.computeCek(ikm, salt); byte[] nonce = WebPushUtil.computeNonce(ikm, salt); return decrypt(cek, nonce, payload); } private  WebPushHybridDecrypt(Builder builder); @Override byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo /* unused */); }
WebPushHybridDecrypt implements HybridDecrypt { @Override public byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo ) throws GeneralSecurityException { if (contextInfo != null) { throw new GeneralSecurityException("contextInfo must be null because it is unused"); } if (ciphertext.length < WebPushConstants.CIPHERTEXT_OVERHEAD) { throw new GeneralSecurityException("ciphertext too short"); } if (ciphertext.length > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("ciphertext too long"); } ByteBuffer record = ByteBuffer.wrap(ciphertext); byte[] salt = new byte[WebPushConstants.SALT_SIZE]; record.get(salt); int recordSize = record.getInt(); if (recordSize != this.recordSize || recordSize < ciphertext.length || recordSize > WebPushConstants.MAX_CIPHERTEXT_SIZE) { throw new GeneralSecurityException("invalid record size: " + recordSize); } int publicKeySize = (int) record.get(); if (publicKeySize != WebPushConstants.PUBLIC_KEY_SIZE) { throw new GeneralSecurityException("invalid ephemeral public key size: " + publicKeySize); } byte[] asPublicKey = new byte[WebPushConstants.PUBLIC_KEY_SIZE]; record.get(asPublicKey); ECPoint asPublicPoint = EllipticCurves.pointDecode( WebPushConstants.NIST_P256_CURVE_TYPE, WebPushConstants.UNCOMPRESSED_POINT_FORMAT, asPublicKey); byte[] payload = new byte[ciphertext.length - WebPushConstants.CONTENT_CODING_HEADER_SIZE]; record.get(payload); byte[] ecdhSecret = EllipticCurves.computeSharedSecret(recipientPrivateKey, asPublicPoint); byte[] ikm = WebPushUtil.computeIkm(ecdhSecret, authSecret, recipientPublicKey, asPublicKey); byte[] cek = WebPushUtil.computeCek(ikm, salt); byte[] nonce = WebPushUtil.computeNonce(ikm, salt); return decrypt(cek, nonce, payload); } private  WebPushHybridDecrypt(Builder builder); @Override byte[] decrypt(final byte[] ciphertext, final byte[] contextInfo /* unused */);  }