1 /*
   2  * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.crypto.provider;
  27 
  28 import java.security.InvalidKeyException;
  29 
  30 import jdk.internal.HotSpotIntrinsicCandidate;
  31 
  32 /**
  33  * This class represents ciphers in counter (CTR) mode.
  34  *
  35  * <p>This mode is implemented independently of a particular cipher.
  36  * Ciphers to which this mode should apply (e.g., DES) must be
  37  * <i>plugged-in</i> using the constructor.
  38  *
  39  * <p>NOTE: This class does not deal with buffering or padding.
  40  *
  41  * @author Andreas Sterbenz
  42  * @since 1.4.2
  43  */
  44 final class CounterMode extends FeedbackCipher {
  45 
  46     // current counter value
  47     private final byte[] counter;
  48 
  49     // encrypted bytes of the previous counter value
  50     private final byte[] encryptedCounter;
  51 
  52     // number of bytes in encryptedCounter already used up
  53     private int used;
  54 
  55     // variables for save/restore calls
  56     private byte[] counterSave = null;
  57     private byte[] encryptedCounterSave = null;
  58     private int usedSave = 0;
  59 
  60     CounterMode(SymmetricCipher embeddedCipher) {
  61         super(embeddedCipher);
  62         counter = new byte[blockSize];
  63         encryptedCounter = new byte[blockSize];
  64     }
  65 
  66     /**
  67      * Gets the name of the feedback mechanism
  68      *
  69      * @return the name of the feedback mechanism
  70      */
  71     String getFeedback() {
  72         return "CTR";
  73     }
  74 
  75     /**
  76      * Resets the iv to its original value.
  77      * This is used when doFinal is called in the Cipher class, so that the
  78      * cipher can be reused (with its original iv).
  79      */
  80     void reset() {
  81         System.arraycopy(iv, 0, counter, 0, blockSize);
  82         used = blockSize;
  83     }
  84 
  85     /**
  86      * Save the current content of this cipher.
  87      */
  88     void save() {
  89         if (counterSave == null) {
  90             counterSave = new byte[blockSize];
  91             encryptedCounterSave = new byte[blockSize];
  92         }
  93         System.arraycopy(counter, 0, counterSave, 0, blockSize);
  94         System.arraycopy(encryptedCounter, 0, encryptedCounterSave, 0,
  95             blockSize);
  96         usedSave = used;
  97     }
  98 
  99     /**
 100      * Restores the content of this cipher to the previous saved one.
 101      */
 102     void restore() {
 103         System.arraycopy(counterSave, 0, counter, 0, blockSize);
 104         System.arraycopy(encryptedCounterSave, 0, encryptedCounter, 0,
 105             blockSize);
 106         used = usedSave;
 107     }
 108 
 109     /**
 110      * Initializes the cipher in the specified mode with the given key
 111      * and iv.
 112      *
 113      * @param decrypting flag indicating encryption or decryption
 114      * @param algorithm the algorithm name
 115      * @param key the key
 116      * @param iv the iv
 117      *
 118      * @exception InvalidKeyException if the given key is inappropriate for
 119      * initializing this cipher
 120      */
 121     void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)
 122             throws InvalidKeyException {
 123         if ((key == null) || (iv == null) || (iv.length != blockSize)) {
 124             throw new InvalidKeyException("Internal error");
 125         }
 126         this.iv = iv;
 127         reset();
 128         // always encrypt mode for embedded cipher
 129         embeddedCipher.init(false, algorithm, key);
 130     }
 131 
 132     /**
 133      * Performs encryption operation.
 134      *
 135      * <p>The input plain text <code>plain</code>, starting at
 136      * <code>plainOffset</code> and ending at
 137      * <code>(plainOffset + len - 1)</code>, is encrypted.
 138      * The result is stored in <code>cipher</code>, starting at
 139      * <code>cipherOffset</code>.
 140      *
 141      * @param in the buffer with the input data to be encrypted
 142      * @param inOffset the offset in <code>plain</code>
 143      * @param len the length of the input data
 144      * @param out the buffer for the result
 145      * @param outOff the offset in <code>cipher</code>
 146      * @return the length of the encrypted data
 147      */
 148     int encrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
 149         return crypt(in, inOff, len, out, outOff);
 150     }
 151 
 152     // CTR encrypt and decrypt are identical
 153     int decrypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
 154         return crypt(in, inOff, len, out, outOff);
 155     }
 156 
 157     /**
 158      * Increment the counter value.
 159      */
 160     private static void increment(byte[] b) {
 161         int n = b.length - 1;
 162         while ((n >= 0) && (++b[n] == 0)) {
 163             n--;
 164         }
 165     }
 166 
 167     /**
 168      * Do the actual encryption/decryption operation.
 169      * Essentially we XOR the input plaintext/ciphertext stream with a
 170      * keystream generated by encrypting the counter values. Counter values
 171      * are encrypted on demand.
 172      */
 173     @HotSpotIntrinsicCandidate
 174     private int crypt(byte[] in, int inOff, int len, byte[] out, int outOff) {
 175         int result = len;
 176         while (len-- > 0) {
 177             if (used >= blockSize) {
 178                 embeddedCipher.encryptBlock(counter, 0, encryptedCounter, 0);
 179                 increment(counter);
 180                 used = 0;
 181             }
 182             out[outOff++] = (byte)(in[inOff++] ^ encryptedCounter[used++]);
 183         }
 184         return result;
 185     }
 186 }