/**
   * Process the <em>Clear</em> part of the message.
   *
   * @param in a byte array containing the <em>Clear</em> part of the message.
   * @param offset the starting index in <code>in</code> where the <em>Clear</em> message bytes
   *     should be considered.
   * @param length the count of bytes in <code>in</code>, starting from <code>offset</code> to
   *     consider.
   * @throws IllegalStateException if no start-of-message method has been invoked earlier or the
   *     Integrity Protection service has not been activated.
   */
  public void doClear(byte[] in, int offset, int length) {
    if (!ready) {
      throw new IllegalStateException();
    }
    if (!wantIntegrity) {
      throw new IllegalStateException();
    }

    mac.update(in, offset, length);
  }
  /**
   * Process the <em>Opaque</em> part of the message.
   *
   * @param in a byte array containing the <em>Clear</em> part of the message.
   * @param inOffset the starting index in <code>in</code> where the <em>Opaque</em> message bytes
   *     should be considered.
   * @param length the count of bytes in <code>in</code>, starting from <code>inOffset</code> to
   *     consider.
   * @param out the byte array where the enciphered opaque message should be stored.
   * @param outOffset the starting offset in <code>out</code> where the enciphered bytes should be
   *     stored.
   * @throws IllegalStateException if no start-of-message method has been invoked earlier.
   * @throws LimitReachedException if one or both of the underlying keystream generators have
   *     reached their limit.
   */
  public void doOpaque(byte[] in, int inOffset, int length, byte[] out, int outOffset)
      throws LimitReachedException {
    if (!ready) {
      throw new IllegalStateException();
    }
    if (wantIntegrity) {
      mac.update(in, inOffset, length);
    }

    if (wantConfidentiality) {
      byte[] suffix = new byte[length];
      cpStream.nextBytes(suffix, 0, length);
      for (int i = 0; i < length; ) {
        out[outOffset++] = (byte) (in[inOffset++] ^ suffix[i++]);
      }
    } else {
      System.arraycopy(in, inOffset, out, outOffset, length);
    }
  }