/*
 * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/**
 * @test
 * @bug 6582580
 * @summary doFinal(clearBuffer, outBuffer) fails when outputbuffer
 * has a position > 0
 */

import java.nio.ByteBuffer;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class EncryptionBug {

    // set this buffer to at least 4096 bytes for the bug to appear
    static int BUFFER_LENGTH = 4111;

    //set this offset to >0 for the bug to appear
    static int OUTPUT_OFFSET = 4;

    public static void main(String[] args) {
        byte[] encryptionKey = new byte[16];
        new Random().nextBytes(encryptionKey);

        Cipher cipherEncrypt;
        try {
            SecretKeySpec skeySpec = new SecretKeySpec(encryptionKey, "AES");
            cipherEncrypt = Cipher.getInstance("AES");
            Cipher cipherDecrypt = Cipher.getInstance("AES");
            cipherEncrypt.init(Cipher.ENCRYPT_MODE, skeySpec);
            cipherDecrypt.init(Cipher.DECRYPT_MODE, skeySpec);
            
            byte data[] = new byte[BUFFER_LENGTH];
            new Random().nextBytes(data);

            ByteBuffer outBuffer = ByteBuffer.allocateDirect(65536);

            ByteBuffer clearBuffer = outBuffer.duplicate();

            clearBuffer.put(data);
            clearBuffer.flip();

            outBuffer.position(OUTPUT_OFFSET);

            int length = cipherEncrypt.doFinal(clearBuffer, outBuffer);

            byte[] encryptedBuffer = new byte[length];

            for (int i = 0; i < encryptedBuffer.length; i++) {
                encryptedBuffer[i] = outBuffer.get(OUTPUT_OFFSET + i);
            }

            byte encryptedDirect[] = cipherEncrypt.doFinal(data);

            for (int i = 0; i < encryptedBuffer.length; i++) {

                if (encryptedDirect[i] != encryptedBuffer[i]) {
                    throw new Exception("********* corrupted index " + i + " "
                            + encryptedBuffer[i] + " vs " + encryptedDirect[i]);
                }
            }
            System.out.println("Test Passed");
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}