Example #1
0
  private void reset(boolean clearMac) {
    cipher.reset();

    S = new byte[BLOCK_SIZE];
    S_at = new byte[BLOCK_SIZE];
    S_atPre = new byte[BLOCK_SIZE];
    atBlock = new byte[BLOCK_SIZE];
    atBlockPos = 0;
    atLength = 0;
    atLengthPre = 0;
    counter = Arrays.clone(J0);
    bufOff = 0;
    totalLength = 0;

    if (bufBlock != null) {
      Arrays.fill(bufBlock, (byte) 0);
    }

    if (clearMac) {
      macBlock = null;
    }

    if (initialAssociatedText != null) {
      processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
    }
  }
Example #2
0
  /**
   * NOTE: MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default
   * is 128 bits. Sizes less than 96 are not recommended, but are supported for specialized
   * applications.
   */
  @Override
  public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException {
    this.forEncryption = forEncryption;
    this.macBlock = null;

    KeyParameter keyParam;

    if (params instanceof AEADParameters) {
      AEADParameters param = (AEADParameters) params;

      nonce = param.getNonce();
      initialAssociatedText = param.getAssociatedText();

      int macSizeBits = param.getMacSize();
      if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0) {
        throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
      }

      macSize = macSizeBits / 8;
      keyParam = param.getKey();
    } else if (params instanceof ParametersWithIV) {
      ParametersWithIV param = (ParametersWithIV) params;

      nonce = param.getIV();
      initialAssociatedText = null;
      macSize = 16;
      keyParam = (KeyParameter) param.getParameters();
    } else {
      throw new IllegalArgumentException("invalid parameters passed to GCM");
    }

    int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
    this.bufBlock = new byte[bufLength];

    if (nonce == null || nonce.length < 1) {
      throw new IllegalArgumentException("IV must be at least 1 byte");
    }

    // TODO Restrict macSize to 16 if nonce length not 12?

    // Cipher always used in forward mode
    // if keyParam is null we're reusing the last key.
    if (keyParam != null) {
      cipher.init(true, keyParam);

      this.H = new byte[BLOCK_SIZE];
      cipher.processBlock(H, 0, H, 0);

      // GCMMultiplier tables don't change unless the key changes (and are expensive to init)
      multiplier.init(H);
      exp = null;
    } else if (this.H == null) {
      throw new IllegalArgumentException("Key must be specified in initial init");
    }

    this.J0 = new byte[BLOCK_SIZE];

    if (nonce.length == 12) {
      System.arraycopy(nonce, 0, J0, 0, nonce.length);
      this.J0[BLOCK_SIZE - 1] = 0x01;
    } else {
      gHASH(J0, nonce, nonce.length);
      byte[] X = new byte[BLOCK_SIZE];
      Pack.longToBigEndian((long) nonce.length * 8, X, 8);
      gHASHBlock(J0, X);
    }

    this.S = new byte[BLOCK_SIZE];
    this.S_at = new byte[BLOCK_SIZE];
    this.S_atPre = new byte[BLOCK_SIZE];
    this.atBlock = new byte[BLOCK_SIZE];
    this.atBlockPos = 0;
    this.atLength = 0;
    this.atLengthPre = 0;
    this.counter = Arrays.clone(J0);
    this.bufOff = 0;
    this.totalLength = 0;

    if (initialAssociatedText != null) {
      processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
    }
  }
Example #3
0
  @Override
  public int doFinal(byte[] out, int outOff)
      throws IllegalStateException, InvalidCipherTextException {
    if (totalLength == 0) {
      initCipher();
    }

    int extra = bufOff;

    if (forEncryption) {
      if (out.length < (outOff + extra + macSize)) {
        throw new OutputLengthException("Output buffer too short");
      }
    } else {
      if (extra < macSize) {
        throw new InvalidCipherTextException("data too short");
      }
      extra -= macSize;

      if (out.length < (outOff + extra)) {
        throw new OutputLengthException("Output buffer too short");
      }
    }

    if (extra > 0) {
      gCTRPartial(bufBlock, 0, extra, out, outOff);
    }

    atLength += atBlockPos;

    if (atLength > atLengthPre) {
      /*
       * Some AAD was sent after the cipher started. We determine the difference b/w the hash value
       * we actually used when the cipher started (S_atPre) and the final hash value calculated
       * (S_at). Then we carry this difference forward by multiplying by H^c, where c is the number
       * of (full or partial) cipher-text blocks produced, and adjust the current hash.
       */

      // Finish hash for partial AAD block
      if (atBlockPos > 0) {
        gHASHPartial(S_at, atBlock, 0, atBlockPos);
      }

      // Find the difference between the AAD hashes
      if (atLengthPre > 0) {
        GCMUtil.xor(S_at, S_atPre);
      }

      // Number of cipher-text blocks produced
      long c = ((totalLength * 8) + 127) >>> 7;

      // Calculate the adjustment factor
      byte[] H_c = new byte[16];
      if (exp == null) {
        exp = new Tables1kGCMExponentiator();
        exp.init(H);
      }
      exp.exponentiateX(c, H_c);

      // Carry the difference forward
      GCMUtil.multiply(S_at, H_c);

      // Adjust the current hash
      GCMUtil.xor(S, S_at);
    }

    // Final gHASH
    byte[] X = new byte[BLOCK_SIZE];
    Pack.longToBigEndian(atLength * 8, X, 0);
    Pack.longToBigEndian(totalLength * 8, X, 8);

    gHASHBlock(S, X);

    // T = MSBt(GCTRk(J0,S))
    byte[] tag = new byte[BLOCK_SIZE];
    cipher.processBlock(J0, 0, tag, 0);
    GCMUtil.xor(tag, S);

    int resultLen = extra;

    // We place into macBlock our calculated value for T
    this.macBlock = new byte[macSize];
    System.arraycopy(tag, 0, macBlock, 0, macSize);

    if (forEncryption) {
      // Append T to the message
      System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
      resultLen += macSize;
    } else {
      // Retrieve the T value from the message and compare to calculated one
      byte[] msgMac = new byte[macSize];
      System.arraycopy(bufBlock, extra, msgMac, 0, macSize);
      if (!Arrays.constantTimeAreEqual(this.macBlock, msgMac)) {
        throw new InvalidCipherTextException("mac check in GCM failed");
      }
    }

    reset(false);

    return resultLen;
  }
Example #4
0
 @Override
 public byte[] getMac() {
   return Arrays.clone(macBlock);
 }