Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/com/sun/crypto/provider/Cipher/AEAD/SameBuffer.java
38889 views
/*1* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.nio.ByteBuffer;24import java.security.AlgorithmParameters;25import java.security.Provider;26import java.security.Security;27import javax.crypto.SecretKey;28import javax.crypto.Cipher;29import javax.crypto.KeyGenerator;30import javax.crypto.spec.GCMParameterSpec;3132/*33* @test34* @bug 804859635* @summary Check if AEAD operations work correctly when buffers used36* for storing plain text and cipher text are overlapped or the same37*/38public class SameBuffer {3940private static final String PROVIDER = "SunJCE";41private static final String AES = "AES";42private static final String GCM = "GCM";43private static final String PADDING = "NoPadding";44private static final int OFFSET = 2;45private static final int OFFSETS = 4;46private static final int KEY_LENGTHS[] = { 128, 192, 256 };47private static final int TEXT_LENGTHS[] = { 0, 1024 };48private static final int AAD_LENGTHS[] = { 0, 1024 };4950private final Provider provider;51private final SecretKey key;52private final String transformation;53private final int textLength;54private final int AADLength;5556/**57* Constructor of the test58*59* @param provider security provider60* @param keyStrength key length61* @param textLength length of data62* @param AADLength AAD length63*/64public SameBuffer(Provider provider, String algorithm, String mode,65String padding, int keyStrength, int textLength, int AADLength)66throws Exception {6768// init a secret key69KeyGenerator kg = KeyGenerator.getInstance(algorithm, provider);70kg.init(keyStrength);71key = kg.generateKey();7273this.transformation = algorithm + "/" + mode + "/" + padding;74this.provider = provider;75this.textLength = textLength;76this.AADLength = AADLength;77}7879public static void main(String[] args) throws Exception {80Provider p = Security.getProvider(PROVIDER);81for (int keyLength : KEY_LENGTHS) {82for (int textLength : TEXT_LENGTHS) {83for (int AADLength : AAD_LENGTHS) {84for (int i = 0; i < OFFSETS; i++) {85// try different offsets86int offset = i * OFFSET;87runTest(p, AES, GCM, PADDING, keyLength, textLength,88AADLength, offset);89}90}91}92}93}9495/*96* Run single test case with given parameters97*/98static void runTest(Provider p, String algo, String mode,99String padding, int keyLength, int textLength, int AADLength,100int offset) throws Exception {101System.out.println("Testing " + keyLength + " key length; "102+ textLength + " text lenght; " + AADLength + " AAD length; "103+ offset + " offset");104if (keyLength > Cipher.getMaxAllowedKeyLength(algo)) {105// skip this if this key length is larger than what's106// configured in the jce jurisdiction policy files107return;108}109SameBuffer test = new SameBuffer(p, algo, mode,110padding, keyLength, textLength, AADLength);111112/*113* There are four test cases:114* 1. AAD and text are placed in separated byte arrays115* 2. AAD and text are placed in the same byte array116* 3. AAD and text are placed in separated byte buffers117* 4. AAD and text are placed in the same byte buffer118*/119Cipher ci = test.createCipher(Cipher.ENCRYPT_MODE, null);120AlgorithmParameters params = ci.getParameters();121test.doTestWithSeparateArrays(offset, params);122test.doTestWithSameArrays(offset, params);123test.doTestWithSeparatedBuffer(offset, params);124test.doTestWithSameBuffer(offset, params);125}126127/*128* Run the test in case when AAD and text are placed in separated byte129* arrays.130*/131private void doTestWithSeparateArrays(int offset,132AlgorithmParameters params) throws Exception {133// prepare buffers to test134Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);135int outputLength = c.getOutputSize(textLength);136int outputBufSize = outputLength + offset * 2;137138byte[] inputText = Helper.generateBytes(outputBufSize);139byte[] AAD = Helper.generateBytes(AADLength);140141// do the test142runGCMWithSeparateArray(Cipher.ENCRYPT_MODE, AAD, inputText, offset * 2,143textLength, offset, params);144int tagLength = c.getParameters()145.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;146runGCMWithSeparateArray(Cipher.DECRYPT_MODE, AAD, inputText, offset,147textLength + tagLength, offset, params);148}149150/**151* Run the test in case when AAD and text are placed in the same byte152* array.153*/154private void doTestWithSameArrays(int offset, AlgorithmParameters params)155throws Exception {156// prepare buffers to test157Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);158int outputLength = c.getOutputSize(textLength);159int outputBufSize = AADLength + outputLength + offset * 2;160161byte[] AAD_and_text = Helper.generateBytes(outputBufSize);162163// do the test164runGCMWithSameArray(Cipher.ENCRYPT_MODE, AAD_and_text, AADLength + offset,165textLength, params);166int tagLength = c.getParameters()167.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;168runGCMWithSameArray(Cipher.DECRYPT_MODE, AAD_and_text, AADLength + offset,169textLength + tagLength, params);170}171172/*173* Run the test in case when AAD and text are placed in separated ByteBuffer174*/175private void doTestWithSeparatedBuffer(int offset,176AlgorithmParameters params) throws Exception {177// prepare AAD byte buffers to test178byte[] AAD = Helper.generateBytes(AADLength);179ByteBuffer AAD_Buf = ByteBuffer.allocate(AADLength);180AAD_Buf.put(AAD, 0, AAD.length);181AAD_Buf.flip();182183// prepare text byte buffer to encrypt/decrypt184Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);185int outputLength = c.getOutputSize(textLength);186int outputBufSize = outputLength + offset;187byte[] inputText = Helper.generateBytes(outputBufSize);188ByteBuffer plainTextBB = ByteBuffer.allocateDirect(inputText.length);189plainTextBB.put(inputText);190plainTextBB.position(offset);191plainTextBB.limit(offset + textLength);192193// do test194runGCMWithSeparateBuffers(Cipher.ENCRYPT_MODE, AAD_Buf, plainTextBB, offset,195textLength, params);196int tagLength = c.getParameters()197.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;198plainTextBB.position(offset);199plainTextBB.limit(offset + textLength + tagLength);200runGCMWithSeparateBuffers(Cipher.DECRYPT_MODE, AAD_Buf, plainTextBB, offset,201textLength + tagLength, params);202}203204/*205* Run the test in case when AAD and text are placed in the same ByteBuffer206*/207private void doTestWithSameBuffer(int offset, AlgorithmParameters params)208throws Exception {209// calculate output length210Cipher c = createCipher(Cipher.ENCRYPT_MODE, params);211int outputLength = c.getOutputSize(textLength);212213// prepare byte buffer contained AAD and plain text214int bufSize = AADLength + offset + outputLength;215byte[] AAD_and_Text = Helper.generateBytes(bufSize);216ByteBuffer AAD_and_Text_Buf = ByteBuffer.allocate(bufSize);217AAD_and_Text_Buf.put(AAD_and_Text, 0, AAD_and_Text.length);218219// do test220runGCMWithSameBuffer(Cipher.ENCRYPT_MODE, AAD_and_Text_Buf, offset,221textLength, params);222int tagLength = c.getParameters()223.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;224AAD_and_Text_Buf.limit(AADLength + offset + textLength + tagLength);225runGCMWithSameBuffer(Cipher.DECRYPT_MODE, AAD_and_Text_Buf, offset,226textLength + tagLength, params);227228}229230/*231* Execute GCM encryption/decryption of a text placed in a byte array.232* AAD is placed in the separated byte array.233* Data are processed twice:234* - in a separately allocated buffer235* - in the text buffer236* Check if two results are equal237*/238private void runGCMWithSeparateArray(int mode, byte[] AAD, byte[] text,239int txtOffset, int lenght, int offset, AlgorithmParameters params)240throws Exception {241// first, generate the cipher text at an allocated buffer242Cipher cipher = createCipher(mode, params);243cipher.updateAAD(AAD);244byte[] outputText = cipher.doFinal(text, txtOffset, lenght);245246// new cipher for encrypt operation247Cipher anotherCipher = createCipher(mode, params);248anotherCipher.updateAAD(AAD);249250// next, generate cipher text again at the same buffer of plain text251int myoff = offset;252int off = anotherCipher.update(text, txtOffset, lenght, text, myoff);253anotherCipher.doFinal(text, myoff + off);254255// check if two resutls are equal256if (!isEqual(text, myoff, outputText, 0, outputText.length)) {257throw new RuntimeException("Two results not equal, mode:" + mode);258}259}260261/*262* Execute GCM encrption/decryption of a text. The AAD and text to process263* are placed in the same byte array. Data are processed twice:264* - in a separetly allocated buffer265* - in a buffer that shares content of the AAD_and_Text_BA266* Check if two results are equal267*/268private void runGCMWithSameArray(int mode, byte[] array, int txtOffset,269int length, AlgorithmParameters params) throws Exception {270// first, generate cipher text at an allocated buffer271Cipher cipher = createCipher(mode, params);272cipher.updateAAD(array, 0, AADLength);273byte[] outputText = cipher.doFinal(array, txtOffset, length);274275// new cipher for encrypt operation276Cipher anotherCipher = createCipher(mode, params);277anotherCipher.updateAAD(array, 0, AADLength);278279// next, generate cipher text again at the same buffer of plain text280int off = anotherCipher.update(array, txtOffset, length,281array, txtOffset);282anotherCipher.doFinal(array, txtOffset + off);283284// check if two results are equal or not285if (!isEqual(array, txtOffset, outputText, 0,286outputText.length)) {287throw new RuntimeException(288"Two results are not equal, mode:" + mode);289}290}291292/*293* Execute GCM encryption/decryption of textBB. AAD and text to process are294* placed in different byte buffers. Data are processed twice:295* - in a separately allocated buffer296* - in a buffer that shares content of the textBB297* Check if results are equal298*/299private void runGCMWithSeparateBuffers(int mode, ByteBuffer buffer,300ByteBuffer textBB, int txtOffset, int dataLength,301AlgorithmParameters params) throws Exception {302// take offset into account303textBB.position(txtOffset);304textBB.mark();305306// first, generate the cipher text at an allocated buffer307Cipher cipher = createCipher(mode, params);308cipher.updateAAD(buffer);309buffer.flip();310ByteBuffer outBB = ByteBuffer.allocateDirect(311cipher.getOutputSize(dataLength));312313cipher.doFinal(textBB, outBB);// get cipher text in outBB314outBB.flip();315316// restore positions317textBB.reset();318319// next, generate cipher text again in a buffer that shares content320Cipher anotherCipher = createCipher(mode, params);321anotherCipher.updateAAD(buffer);322buffer.flip();323ByteBuffer buf2 = textBB.duplicate(); // buf2 shares textBuf context324buf2.limit(txtOffset + anotherCipher.getOutputSize(dataLength));325int dataProcessed2 = anotherCipher.doFinal(textBB, buf2);326buf2.position(txtOffset);327buf2.limit(txtOffset + dataProcessed2);328329if (!buf2.equals(outBB)) {330throw new RuntimeException(331"Two results are not equal, mode:" + mode);332}333}334335/*336* Execute GCM encryption/decryption of text. AAD and a text to process are337* placed in the same buffer. Data is processed twice:338* - in a separately allocated buffer339* - in a buffer that shares content of the AAD_and_Text_BB340*/341private void runGCMWithSameBuffer(int mode, ByteBuffer buffer,342int txtOffset, int length, AlgorithmParameters params)343throws Exception {344345// allocate a separate buffer346Cipher cipher = createCipher(mode, params);347ByteBuffer outBB = ByteBuffer.allocateDirect(348cipher.getOutputSize(length));349350// first, generate the cipher text at an allocated buffer351buffer.flip();352buffer.limit(AADLength);353cipher.updateAAD(buffer);354buffer.limit(AADLength + txtOffset + length);355buffer.position(AADLength + txtOffset);356cipher.doFinal(buffer, outBB);357outBB.flip(); // cipher text in outBB358359// next, generate cipherText again in the same buffer360Cipher anotherCipher = createCipher(mode, params);361buffer.flip();362buffer.limit(AADLength);363anotherCipher.updateAAD(buffer);364buffer.limit(AADLength + txtOffset + length);365buffer.position(AADLength + txtOffset);366367// share textBuf context368ByteBuffer buf2 = buffer.duplicate();369buf2.limit(AADLength + txtOffset + anotherCipher.getOutputSize(length));370int dataProcessed2 = anotherCipher.doFinal(buffer, buf2);371buf2.position(AADLength + txtOffset);372buf2.limit(AADLength + txtOffset + dataProcessed2);373374if (!buf2.equals(outBB)) {375throw new RuntimeException(376"Two results are not equal, mode:" + mode);377}378}379380private boolean isEqual(byte[] A, int offsetA, byte[] B, int offsetB,381int bytesToCompare) {382System.out.println("offsetA: " + offsetA + " offsetB: " + offsetA383+ " bytesToCompare: " + bytesToCompare);384for (int i = 0; i < bytesToCompare; i++) {385int setA = i + offsetA;386int setB = i + offsetB;387if (setA > A.length - 1 || setB > B.length - 1388|| A[setA] != B[setB]) {389return false;390}391}392393return true;394}395396/*397* Creates a Cipher object for testing: for encryption it creates new Cipher398* based on previously saved parameters (it is prohibited to use the same399* Cipher twice for encription during GCM mode), or returns initiated400* existing Cipher.401*/402private Cipher createCipher(int mode, AlgorithmParameters params)403throws Exception {404Cipher cipher = Cipher.getInstance(transformation, provider);405if (Cipher.ENCRYPT_MODE == mode) {406// initiate it with the saved parameters407if (params != null) {408cipher.init(Cipher.ENCRYPT_MODE, key, params);409} else {410// intiate the cipher and save parameters411cipher.init(Cipher.ENCRYPT_MODE, key);412}413} else if (cipher != null) {414cipher.init(Cipher.DECRYPT_MODE, key, params);415} else {416throw new RuntimeException("Can't create cipher");417}418419return cipher;420}421422}423424425