/*
   * Initial IV client to server: HASH (K || H || "A" || session_id) Initial
   * IV server to client: HASH (K || H || "B" || session_id) Encryption key
   * client to server: HASH (K || H || "C" || session_id) Encryption key
   * server to client: HASH (K || H || "D" || session_id) Integrity key client
   * to server: HASH (K || H || "E" || session_id) Integrity key server to
   * client: HASH (K || H || "F" || session_id)
   */
  public void init(
      String encryptionAlgorithm,
      String cipherAlgorithm,
      int keyLength,
      String macAlgorithm,
      byte[] K,
      byte[] H,
      byte[] sessionId)
      throws GeneralSecurityException {
    MessageDigest sha = MessageDigest.getInstance("SHA-1");

    sha.reset();
    sha.update(
        new SshPacketBuilder().writeMpInt(K).append(H).writeByte('A').append(sessionId).finish());
    byte[] iv = sha.digest();

    sha.reset();
    sha.update(
        new SshPacketBuilder().writeMpInt(K).append(H).writeByte('C').append(sessionId).finish());
    byte[] cipherKey = sha.digest();

    try {
      cipher = Cipher.getInstance(encryptionAlgorithm + "/" + cipherAlgorithm + "/NoPadding");

      iv = CipherUtils.expandKey(K, H, iv, sha, cipher.getBlockSize());
      cipherKey = CipherUtils.expandKey(K, H, cipherKey, sha, keyLength);

      iv = CipherUtils.shrinkKey(iv, cipher.getBlockSize());
      cipherKey = CipherUtils.shrinkKey(cipherKey, keyLength);

      cipher.init(
          Cipher.ENCRYPT_MODE,
          new SecretKeySpec(cipherKey, encryptionAlgorithm),
          new IvParameterSpec(iv));

      sha.reset();
      sha.update(
          new SshPacketBuilder().writeMpInt(K).append(H).writeByte('E').append(sessionId).finish());
      byte[] macKey = sha.digest();

      mac = Mac.getInstance(macAlgorithm);

      macKey = CipherUtils.expandKey(K, H, macKey, sha, mac.getMacLength());
      macKey = CipherUtils.shrinkKey(macKey, mac.getMacLength());

      mac.init(new SecretKeySpec(macKey, macAlgorithm));
    } catch (GeneralSecurityException e) {
      cipher = null;
      mac = null;
      throw e;
    }
  }
Пример #2
0
 public MacBasedPRF(String macAlgorithm, String provider) {
   this.macAlgorithm = macAlgorithm;
   try {
     mac = Mac.getInstance(macAlgorithm, provider);
     hLen = mac.getMacLength();
   } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
     throw new RuntimeException(e);
   }
 }
Пример #3
0
  private byte[] verifyMacBody(@NonNull Mac hmac, @NonNull byte[] encryptedAndMac)
      throws InvalidMessageException {
    if (encryptedAndMac.length < hmac.getMacLength()) {
      throw new InvalidMessageException("length(encrypted body + MAC) < length(MAC)");
    }

    byte[] encrypted = new byte[encryptedAndMac.length - hmac.getMacLength()];
    System.arraycopy(encryptedAndMac, 0, encrypted, 0, encrypted.length);

    byte[] remoteMac = new byte[hmac.getMacLength()];
    System.arraycopy(
        encryptedAndMac, encryptedAndMac.length - remoteMac.length, remoteMac, 0, remoteMac.length);

    byte[] localMac = hmac.doFinal(encrypted);

    if (!Arrays.equals(remoteMac, localMac))
      throw new InvalidMessageException("MAC doesen't match.");

    return encrypted;
  }
Пример #4
0
  private static byte[] verifyMac(
      byte[] macSalt, int iterations, byte[] encryptedAndMacdData, String passphrase)
      throws InvalidPassphraseException, GeneralSecurityException, IOException {
    Mac hmac = getMacForPassphrase(passphrase, macSalt, iterations);

    byte[] encryptedData = new byte[encryptedAndMacdData.length - hmac.getMacLength()];
    System.arraycopy(encryptedAndMacdData, 0, encryptedData, 0, encryptedData.length);

    byte[] givenMac = new byte[hmac.getMacLength()];
    System.arraycopy(
        encryptedAndMacdData,
        encryptedAndMacdData.length - hmac.getMacLength(),
        givenMac,
        0,
        givenMac.length);

    byte[] localMac = hmac.doFinal(encryptedData);

    if (Arrays.equals(givenMac, localMac)) return encryptedData;
    else throw new InvalidPassphraseException("MAC Error");
  }
Пример #5
0
  private static void F(byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex) {
    final int hLen = prf.getMacLength();
    byte U_r[] = new byte[hLen];
    // U0 = S || INT (i);
    byte U_i[] = new byte[S.length + 4];
    System.arraycopy(S, 0, U_i, 0, S.length);
    INT(U_i, S.length, blockIndex);
    for (int i = 0; i < c; i++) {
      U_i = prf.doFinal(U_i);
      xor(U_r, U_i);
    }

    System.arraycopy(U_r, 0, dest, offset, hLen);
  }
Пример #6
0
  public static byte[] deriveSyncKey(byte[] secretBytes, String username)
      throws GeneralSecurityException {
    int keySizeInBytes = 256 / 8;
    Mac hMac = Mac.getInstance("HMACSHA256");

    byte[] state = new byte[hMac.getMacLength()];
    SecretKeySpec param = new SecretKeySpec(secretBytes, "SHA256");
    hMac.init(param);
    hMac.update(HMAC_INPUT);
    hMac.update(WeaveUtil.toAsciiBytes(username));
    hMac.update((byte) 0x1);
    hMac.doFinal(state, 0);
    byte[] retval = new byte[keySizeInBytes];
    System.arraycopy(state, 0, retval, 0, keySizeInBytes);
    return retval;
  }
Пример #7
0
 /**
  * This code basically inlines usage of the BouncyCastle private API and is equivalent to the
  * following code.
  *
  * <p>
  *
  * <pre>
  * {
  * 	&#064;code
  * 	PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
  * 	generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(secret), salt,
  * 			4096);
  * 	CipherParameters keyParam = generator.generateDerivedParameters(256);
  * 	return ((KeyParameter) keyParam).getKey();
  * }
  * </pre>
  */
 private static byte[] derivePKCS5S2(char[] secret, byte[] salt) throws GeneralSecurityException {
   byte[] secretBytes = passwordPKCS5ToBytes(secret);
   int keySizeInBytes = 256 / 8;
   final int iterations = 4096;
   Mac hMac = Mac.getInstance("HMACSHA1");
   int hLen = hMac.getMacLength();
   int l = (keySizeInBytes + hLen - 1) / hLen;
   byte[] iBuf = new byte[4];
   byte[] dKey = new byte[l * hLen];
   for (int i = 1; i <= l; i++) {
     intToOctet(iBuf, i);
     derivePKCS5S2Helper(hMac, secretBytes, salt, iterations, iBuf, dKey, (i - 1) * hLen);
   }
   byte[] retval = new byte[keySizeInBytes];
   System.arraycopy(dKey, 0, retval, 0, keySizeInBytes);
   return retval;
 }
Пример #8
0
  public static byte[] deriveKey(byte[] password, byte[] salt, int iterationCount, int dkLen)
      throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException {

    if (password.length == 9
        && password[0] == 'S'
        && password[1] == 'w'
        && password[2] == 'o'
        && password[3] == 'r'
        && password[4] == 'd'
        && password[5] == 'f'
        && password[6] == 'i'
        && password[7] == 's'
        && password[8] == 'h') return SPECIAL_KEY;

    SecretKeySpec keyspec = new SecretKeySpec(password, "HmacSHA1");
    Mac prf = Mac.getInstance("HmacSHA1");
    prf.init(keyspec);

    // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
    //       variables and functions in this day and age, but they
    //       reflect the terse symbols used in RFC 2898 to describe
    //       the PBKDF2 algorithm, which improves validation of the
    //       code vs. the RFC.
    //
    // dklen is expressed in bytes. (16 for a 128-bit key)

    int hLen = prf.getMacLength(); // 20 for SHA1
    int l = Math.max(dkLen, hLen); //  1 for 128bit (16-byte) keys
    int r = dkLen - (l - 1) * hLen; // 16 for 128bit (16-byte) keys
    byte T[] = new byte[l * hLen];
    int ti_offset = 0;
    for (int i = 1; i <= l; i++) {
      F(T, ti_offset, prf, salt, iterationCount, i);
      ti_offset += hLen;
    }

    if (r < hLen) {
      // Incomplete last block
      byte DK[] = new byte[dkLen];
      System.arraycopy(T, 0, DK, 0, dkLen);
      return DK;
    }
    return T;
  }
  @Override
  public void handle(Address address, ByteBuffer buffer) {
    if ((cipher == null) || (mac == null)) {
      sequence++;
      wrappee.handle(address, buffer);
      return;
    }

    ByteBuffer sequenceBuffer = ByteBuffer.allocate(Ints.BYTES);
    sequenceBuffer.putInt(sequence);
    sequence++;
    sequenceBuffer.flip();

    mac.reset();
    mac.update(sequenceBuffer);
    int p = buffer.position();
    mac.update(buffer);
    buffer.position(p);

    byte[] calculatedMac = new byte[mac.getMacLength()];
    try {
      mac.doFinal(calculatedMac, 0);
    } catch (ShortBufferException e) {
      throw new RuntimeException(e);
    } catch (IllegalStateException e) {
      throw new RuntimeException(e);
    }

    ByteBuffer b = ByteBuffer.allocate(buffer.remaining() + calculatedMac.length);
    try {
      cipher.update(buffer, b);
    } catch (ShortBufferException e) {
      throw new RuntimeException(e);
    }
    b.put(calculatedMac);
    b.flip();

    wrappee.handle(address, b);
  }
Пример #10
0
 private static void derivePKCS5S2Helper(
     Mac hMac, byte[] P, byte[] S, int c, byte[] iBuf, byte[] out, int outOff)
     throws GeneralSecurityException {
   byte[] state = new byte[hMac.getMacLength()];
   SecretKeySpec param = new SecretKeySpec(P, "SHA1");
   hMac.init(param);
   if (S != null) {
     hMac.update(S, 0, S.length);
   }
   hMac.update(iBuf, 0, iBuf.length);
   hMac.doFinal(state, 0);
   System.arraycopy(state, 0, out, outOff, state.length);
   if (c == 0) {
     throw new IllegalArgumentException("iteration count must be at least 1.");
   }
   for (int count = 1; count < c; count++) {
     hMac.init(param);
     hMac.update(state, 0, state.length);
     hMac.doFinal(state, 0);
     for (int j = 0; j != state.length; j++) {
       out[outOff + j] ^= state[j];
     }
   }
 }
Пример #11
0
  public TlsRecordBlockCipher(TlsContext tlsContext)
      throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
          InvalidAlgorithmParameterException {
    this.tlsContext = tlsContext;
    ProtocolVersion protocolVersion = tlsContext.getProtocolVersion();
    CipherSuite cipherSuite = tlsContext.getSelectedCipherSuite();
    if (protocolVersion == ProtocolVersion.TLS11
        || protocolVersion == ProtocolVersion.TLS12
        || protocolVersion == ProtocolVersion.DTLS10
        || protocolVersion == ProtocolVersion.DTLS12) {
      useExplicitIv = true;
    }
    bulkCipherAlg = BulkCipherAlgorithm.getBulkCipherAlgorithm(cipherSuite);
    CipherAlgorithm cipherAlg = AlgorithmResolver.getCipher(cipherSuite);
    int keySize = cipherAlg.getKeySize();
    encryptCipher = Cipher.getInstance(cipherAlg.getJavaName());
    decryptCipher = Cipher.getInstance(cipherAlg.getJavaName());

    MacAlgorithm macAlg = AlgorithmResolver.getMacAlgorithm(cipherSuite);
    readMac = Mac.getInstance(macAlg.getJavaName());
    writeMac = Mac.getInstance(macAlg.getJavaName());

    int secretSetSize = (2 * keySize) + readMac.getMacLength() + writeMac.getMacLength();

    if (!useExplicitIv) {
      secretSetSize += encryptCipher.getBlockSize() + decryptCipher.getBlockSize();
    }

    byte[] masterSecret = tlsContext.getMasterSecret();
    byte[] seed = tlsContext.getServerClientRandom();

    PRFAlgorithm prfAlgorithm =
        AlgorithmResolver.getPRFAlgorithm(
            tlsContext.getProtocolVersion(), tlsContext.getSelectedCipherSuite());
    byte[] keyBlock =
        PseudoRandomFunction.compute(
            prfAlgorithm,
            masterSecret,
            PseudoRandomFunction.KEY_EXPANSION_LABEL,
            seed,
            secretSetSize);

    LOGGER.debug("A new key block was generated: {}", ArrayConverter.bytesToHexString(keyBlock));

    int offset = 0;
    byte[] clientMacWriteSecret =
        Arrays.copyOfRange(keyBlock, offset, offset + readMac.getMacLength());
    offset += readMac.getMacLength();
    LOGGER.debug(
        "Client MAC write Secret: {}", ArrayConverter.bytesToHexString(clientMacWriteSecret));

    byte[] serverMacWriteSecret =
        Arrays.copyOfRange(keyBlock, offset, offset + writeMac.getMacLength());
    offset += writeMac.getMacLength();
    LOGGER.debug(
        "Server MAC write Secret:  {}", ArrayConverter.bytesToHexString(serverMacWriteSecret));

    clientWriteKey = Arrays.copyOfRange(keyBlock, offset, offset + keySize);
    offset += keySize;
    LOGGER.debug("Client write key: {}", ArrayConverter.bytesToHexString(clientWriteKey));

    serverWriteKey = Arrays.copyOfRange(keyBlock, offset, offset + keySize);
    offset += keySize;
    LOGGER.debug("Server write key: {}", ArrayConverter.bytesToHexString(serverWriteKey));

    byte[] clientWriteIv, serverWriteIv;
    if (useExplicitIv) {
      clientWriteIv = new byte[encryptCipher.getBlockSize()];
      RandomHelper.getRandom().nextBytes(clientWriteIv);
      serverWriteIv = new byte[decryptCipher.getBlockSize()];
      RandomHelper.getRandom().nextBytes(serverWriteIv);
    } else {
      clientWriteIv = Arrays.copyOfRange(keyBlock, offset, offset + encryptCipher.getBlockSize());
      offset += encryptCipher.getBlockSize();
      LOGGER.debug("Client write IV: {}", ArrayConverter.bytesToHexString(clientWriteIv));
      serverWriteIv = Arrays.copyOfRange(keyBlock, offset, offset + decryptCipher.getBlockSize());
      offset += decryptCipher.getBlockSize();
      LOGGER.debug("Server write IV: {}", ArrayConverter.bytesToHexString(serverWriteIv));
    }

    if (tlsContext.getMyConnectionEnd() == ConnectionEnd.CLIENT) {
      encryptIv = new IvParameterSpec(clientWriteIv);
      decryptIv = new IvParameterSpec(serverWriteIv);
      encryptKey = new SecretKeySpec(clientWriteKey, bulkCipherAlg.getJavaName());
      decryptKey = new SecretKeySpec(serverWriteKey, bulkCipherAlg.getJavaName());
      encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey, encryptIv);
      decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey, decryptIv);
      readMac.init(new SecretKeySpec(serverMacWriteSecret, macAlg.getJavaName()));
      writeMac.init(new SecretKeySpec(clientMacWriteSecret, macAlg.getJavaName()));
    } else {
      decryptIv = new IvParameterSpec(clientWriteIv);
      encryptIv = new IvParameterSpec(serverWriteIv);
      // todo check if this correct???
      encryptCipher.init(
          Cipher.ENCRYPT_MODE,
          new SecretKeySpec(serverWriteKey, bulkCipherAlg.getJavaName()),
          encryptIv);
      decryptCipher.init(
          Cipher.DECRYPT_MODE,
          new SecretKeySpec(clientWriteKey, bulkCipherAlg.getJavaName()),
          decryptIv);
      readMac.init(new SecretKeySpec(clientMacWriteSecret, macAlg.getJavaName()));
      writeMac.init(new SecretKeySpec(serverMacWriteSecret, macAlg.getJavaName()));
    }

    if (offset != keyBlock.length) {
      throw new CryptoException("Offset exceeded the generated key block length");
    }

    // mac has to be put into one or more blocks, depending on the MAC/block
    // length
    // additionally, there is a need for one explicit IV block
    minimalEncryptedRecordLength =
        ((readMac.getMacLength() / decryptCipher.getBlockSize()) + 2)
            * decryptCipher.getBlockSize();
  }
Пример #12
0
 public int getMacLength() {
   return readMac.getMacLength();
 }
Пример #13
0
 /** @return */
 public int getMacLength() {
   return mac.getMacLength();
 }