All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.crypto.provider.GCTR Maven / Gradle / Ivy

There is a newer version: 17.alpha.0.57
Show newest version
/*
 * Copyright (c) 2013, 2020, 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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.
 */

/*
 * (C) Copyright IBM Corp. 2013
 */

package com.sun.crypto.provider;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

/**
 * This class represents the GCTR function defined in NIST 800-38D
 * under section 6.5.  With a given cipher object and initial counter
 * block, a counter mode operation is performed.  Blocksize is limited
 * to 16 bytes.
 *
 * If any invariant is broken, failures can occur because the
 * AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM
 * (see JDK-8067648 for details).
 *
 * The counter mode operations can be intrinsified and parallelized
 * by using CounterMode.implCrypt() if HotSpot VM supports it on the
 * architecture.
 *
 * 

This function is used in the implementation of GCM mode. * * @since 1.8 */ final class GCTR extends CounterMode implements GCM { // Maximum buffer size rotating ByteBuffer->byte[] intrinsic copy private static final int MAX_LEN = 1024; private byte[] block; GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) { super(cipher); if (initialCounterBlk.length != blockSize) { throw new RuntimeException("length of initial counter block (" + initialCounterBlk.length + ") not equal to blockSize (" + blockSize + ")"); } iv = initialCounterBlk; reset(); } @Override String getFeedback() { return "GCTR"; } // return the number of blocks until the lower 32 bits roll over private long blocksUntilRollover() { ByteBuffer buf = ByteBuffer.wrap(counter, counter.length - 4, 4); buf.order(ByteOrder.BIG_ENDIAN); long ctr32 = 0xFFFFFFFFL & buf.getInt(); long blocksLeft = (1L << 32) - ctr32; return blocksLeft; } private void checkBlock() { if (block == null) { block = new byte[blockSize]; } else { Arrays.fill(block, (byte)0); } } /** * Using the given inLen, this operates only on blockSize data, leaving * the remainder in 'in'. * The return value will be (inLen - (inLen % blockSize)) */ public int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { if (inLen == 0) { return 0; } if (inLen - inOfs > in.length) { throw new RuntimeException("input length out of bound"); } if (inLen < 0) { throw new RuntimeException("input length unsupported"); } if (out.length - outOfs < (inLen - (inLen % blockSize))) { throw new RuntimeException("output buffer too small"); } inLen -= inLen % blockSize; long blocksLeft = blocksUntilRollover(); int numOfCompleteBlocks = inLen / blockSize; if (numOfCompleteBlocks >= blocksLeft) { // Counter Mode encryption cannot be used because counter will // roll over incorrectly. Use GCM-specific code instead. checkBlock(); for (int i = 0; i < numOfCompleteBlocks; i++) { embeddedCipher.encryptBlock(counter, 0, block, 0); for (int n = 0; n < blockSize; n++) { int index = (i * blockSize + n); out[outOfs + index] = (byte) ((in[inOfs + index] ^ block[n])); } GaloisCounterMode.increment32(counter); } return inLen; } else { return encrypt(in, inOfs, inLen, out, outOfs); } } /** * Operate on only blocksize data leaving the remainder in 'in' . */ public int update(byte[] in, int inOfs, int inLen, ByteBuffer dst) { // If the bytebuffer is backed by arrays, use that instead of // allocating and copying for direct bytebuffers if (!dst.isDirect()) { int len = update(in, inOfs, inLen, dst.array(), dst.arrayOffset() + dst.position()); dst.position(dst.position() + len); return len; } // Direct ByteBuffer operation if (inLen - inOfs > in.length) { throw new RuntimeException("input length out of bound"); } if (inLen < 0) { throw new RuntimeException("input length unsupported"); } // See GaloisCounterMode. decryptFinal(bytebuffer, bytebuffer) for // details on the check for 'dst' having enough space for the result. long blocksLeft = blocksUntilRollover(); int numOfCompleteBlocks = inLen / blockSize; if (numOfCompleteBlocks >= blocksLeft) { // Counter Mode encryption cannot be used because counter will // roll over incorrectly. Use GCM-specific code instead. checkBlock(); for (int i = 0; i < numOfCompleteBlocks; i++) { embeddedCipher.encryptBlock(counter, 0, block, 0); for (int n = 0; n < blockSize; n++) { int index = (i * blockSize + n); dst.put((byte) ((in[inOfs + index] ^ block[n]))); } GaloisCounterMode.increment32(counter); } return inLen; } else { int len = inLen - inLen % blockSize; int processed = len; byte[] out = new byte[Math.min(MAX_LEN, len)]; int offset = inOfs; while (processed > MAX_LEN) { encrypt(in, offset, MAX_LEN, out, 0); dst.put(out, 0, MAX_LEN); processed -= MAX_LEN; offset += MAX_LEN; } encrypt(in, offset, processed, out, 0); // If dst is less than blocksize, insert only what it can. Extra // bytes would cause buffers with enough size to fail with a // short buffer dst.put(out, 0, Math.min(dst.remaining(), processed)); return len; } } /** * Operate on only blocksize data leaving the remainder in the src buffer. */ public int update(ByteBuffer src, ByteBuffer dst) { int len; // If the bytebuffer is backed by arrays, use that instead of // allocating and copying for direct bytebuffers if (src.hasArray() && dst.hasArray()) { len = update(src.array(), src.arrayOffset() + src.position(), src.remaining() - (src.remaining() % blockSize), dst.array(), dst.arrayOffset() + dst.position()); src.position(src.position() + len); dst.position(dst.position() + len); return len; } // Direct bytebuffer operation long blocksLeft = blocksUntilRollover(); int numOfCompleteBlocks = src.remaining() / blockSize; if (numOfCompleteBlocks >= blocksLeft) { // Counter Mode encryption cannot be used because counter will // roll over incorrectly. Use GCM-specific code instead. checkBlock(); for (int i = 0; i < numOfCompleteBlocks; i++) { embeddedCipher.encryptBlock(counter, 0, block, 0); for (int n = 0; n < blockSize; n++) { dst.put((byte) (src.get() ^ block[n])); } GaloisCounterMode.increment32(counter); } return numOfCompleteBlocks * blockSize; } len = src.remaining() - (src.remaining() % blockSize); int processed = len; byte[] in = new byte[Math.min(MAX_LEN, len)]; while (processed > MAX_LEN) { src.get(in, 0, MAX_LEN); encrypt(in, 0, MAX_LEN, in, 0); dst.put(in, 0, MAX_LEN); processed -= MAX_LEN; } src.get(in, 0, processed); encrypt(in, 0, processed, in, 0); dst.put(in, 0, processed); return len; } /** * doFinal operation by using update() for any full block operations needed, * then operating on the final bytes in the input buffer. * * This method will not write any block padding to the output buffer */ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { if (inLen == 0) { return 0; } int lastBlockSize = inLen % blockSize; int completeBlkLen = inLen - lastBlockSize; // process the complete blocks first update(in, inOfs, completeBlkLen, out, outOfs); if (lastBlockSize != 0) { // do the last partial block checkBlock(); embeddedCipher.encryptBlock(counter, 0, block, 0); for (int n = 0; n < lastBlockSize; n++) { out[outOfs + completeBlkLen + n] = (byte) ((in[inOfs + completeBlkLen + n] ^ block[n])); } } return inLen; } /** * doFinal operation by using update() for any full block operations needed, * then operating on the final bytes in the input buffer. * * If src and dst are array-backed bytebuffers, call doFinal(byte[]...) for * less memory usage. */ public int doFinal(ByteBuffer src, ByteBuffer dst) { // If the bytebuffer is backed by arrays, use that instead of // allocating and copying for direct bytebuffers if (src.hasArray() && dst.hasArray()) { int len = doFinal(src.array(), src.arrayOffset() + src.position(), src.remaining(), dst.array(), dst.arrayOffset() + dst.position()); src.position(src.position() + len); dst.position(dst.position() + len); return len; } int len = src.remaining(); int lastBlockSize = len % blockSize; update(src, dst); if (lastBlockSize != 0) { checkBlock(); // do the last partial block embeddedCipher.encryptBlock(counter, 0, block, 0); for (int n = 0; n < lastBlockSize; n++) { dst.put((byte) (src.get() ^ block[n])); } } return len; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy