public static final byte[] apply(byte[] ikm, byte[] salt, byte[] info, Supplier<Digest> digestSupplier, int keyLengthBytes) { logger.trace("<< apply() - ikm: 0x{} salt: 0x{} info: 0x{} digestSupplier: {} keyLengthBytes: {}", Hex.toHexString(ikm), Hex.toHexString(salt), Hex.toHexString(info), digestSupplier, keyLengthBytes); Digest hash = digestSupplier.get(); byte[] okm = new byte[keyLengthBytes]; HKDFParameters params = new HKDFParameters(ikm, salt, info); HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); hkdf.init(params); hkdf.generateBytes(okm, 0, keyLengthBytes); logger.trace(">> apply() - output keying material: 0x{}", Hex.toHexString(okm)); return okm; }
private HttpResponse createUser(byte[] username, byte[] ltpk, byte[] proof) throws Exception { HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); hkdf.init(new HKDFParameters(k, "Pair-Setup-Controller-Sign-Salt".getBytes(StandardCharsets.UTF_8), "Pair-Setup-Controller-Sign-Info".getBytes(StandardCharsets.UTF_8))); byte[] okm = new byte[32]; hkdf.generateBytes(okm, 0, 32); byte[] completeData = ByteUtils.joinBytes(okm, username, ltpk); if (!new EdsaVerifier(ltpk).verify(completeData, proof)) { throw new Exception("Invalid signature"); } authInfo.createUser(authInfo.getMac()+new String(username, StandardCharsets.UTF_8), ltpk); advertiser.setDiscoverable(false); return createResponse(); }
StreamCipherTransformer(File salt) { super(salt); additSalt = new File(salt.getParent(), "streamCipherSalt"); rand = new SecureRandom(); algName = Configuration.getString(ALG_NAME); if (algName == null) { algName = "ChaCha"; } String hkdf = Configuration.getString(HKDF_ALG); if (hkdf == null) { hkdf = "SHA512"; } this.hkdf = new HKDFBytesGenerator(Digesters.getDigester(hkdf)); }
BlockCipherMacTransformer(File salt) { super(salt); enc = BlockCiphers.getEncryptor(Configuration.getString(ENCRYPTION_ALG_NAME), Configuration.getString(ENCRYPTION_MODE), Configuration.getString(ENCRYPTION_PADDING)); rand = new SecureRandom(); String hkdf = Configuration.getString(HKDF_ALGORITHM); if (hkdf == null || hkdf.length() == 0) { hkdf = "SHA256"; } this.hkdf = new HKDFBytesGenerator(Digesters.getDigester(hkdf)); salts = new IOFile(new File(salt.getParentFile(), "additionalSalts"), new TextIOStreamHandler()); }
/** * Convenience method for computing the HMAC Key Derivation Function. The * real work is offloaded to BouncyCastle. */ protected static byte[] hkdfExpand(byte[] ikm, byte[] salt, byte[] info, int length) throws InvalidKeyException, NoSuchAlgorithmException { HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA256Digest()); hkdf.init(new HKDFParameters(ikm, salt, info)); byte[] okm = new byte[length]; hkdf.generateBytes(okm, 0, length); return okm; }
public HttpResponse handle(PairSetupRequest req) throws Exception { HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); hkdf.init(new HKDFParameters(k, "Pair-Setup-Encrypt-Salt".getBytes(StandardCharsets.UTF_8), "Pair-Setup-Encrypt-Info".getBytes(StandardCharsets.UTF_8))); byte[] okm = hkdf_enc_key = new byte[32]; hkdf.generateBytes(okm, 0, 32); return decrypt((Stage3Request) req, okm); }
private HttpResponse createResponse() throws Exception { HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); hkdf.init(new HKDFParameters(k, "Pair-Setup-Accessory-Sign-Salt".getBytes(StandardCharsets.UTF_8), "Pair-Setup-Accessory-Sign-Info".getBytes(StandardCharsets.UTF_8))); byte[] okm = new byte[32]; hkdf.generateBytes(okm, 0, 32); EdsaSigner signer = new EdsaSigner(authInfo.getPrivateKey()); byte[] material = ByteUtils.joinBytes(okm, authInfo.getMac().getBytes(StandardCharsets.UTF_8), signer.getPublicKey()); byte[] proof = signer.sign(material); Encoder encoder = TypeLengthValueUtils.getEncoder(); encoder.add(MessageType.USERNAME, authInfo.getMac().getBytes(StandardCharsets.UTF_8)); encoder.add(MessageType.PUBLIC_KEY, signer.getPublicKey()); encoder.add(MessageType.SIGNATURE, proof); byte[] plaintext = encoder.toByteArray(); ChachaEncoder chacha = new ChachaEncoder(hkdf_enc_key, "PS-Msg06".getBytes(StandardCharsets.UTF_8)); byte[] ciphertext = chacha.encodeCiphertext(plaintext); encoder = TypeLengthValueUtils.getEncoder(); encoder.add(MessageType.STATE, (short) 6); encoder.add(MessageType.ENCRYPTED_DATA, ciphertext); return new PairingResponse(encoder.toByteArray()); }
private HttpResponse stage1(Stage1Request request) throws Exception { logger.debug("Starting pair verification for "+registry.getLabel()); clientPublicKey = request.getClientPublicKey(); publicKey = new byte[32]; byte[] privateKey = new byte[32]; getSecureRandom().nextBytes(privateKey); Curve25519.keygen(publicKey, null, privateKey); sharedSecret = new byte[32]; Curve25519.curve(sharedSecret, privateKey, clientPublicKey); byte[] material = ByteUtils.joinBytes(publicKey, authInfo.getMac().getBytes(StandardCharsets.UTF_8), clientPublicKey); byte[] proof = new EdsaSigner(authInfo.getPrivateKey()).sign(material); HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); hkdf.init(new HKDFParameters(sharedSecret, "Pair-Verify-Encrypt-Salt".getBytes(StandardCharsets.UTF_8), "Pair-Verify-Encrypt-Info".getBytes(StandardCharsets.UTF_8))); hkdfKey = new byte[32]; hkdf.generateBytes(hkdfKey, 0, 32); Encoder encoder = TypeLengthValueUtils.getEncoder(); encoder.add(MessageType.USERNAME, authInfo.getMac().getBytes(StandardCharsets.UTF_8)); encoder.add(MessageType.SIGNATURE, proof); byte[] plaintext = encoder.toByteArray(); ChachaEncoder chacha = new ChachaEncoder(hkdfKey, "PV-Msg02".getBytes(StandardCharsets.UTF_8)); byte[] ciphertext = chacha.encodeCiphertext(plaintext); encoder = TypeLengthValueUtils.getEncoder(); encoder.add(MessageType.STATE, (short) 2); encoder.add(MessageType.ENCRYPTED_DATA, ciphertext); encoder.add(MessageType.PUBLIC_KEY, publicKey); return new PairingResponse(encoder.toByteArray()); }
private byte[] createKey(String info) { HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA512Digest()); hkdf.init(new HKDFParameters(sharedSecret, "Control-Salt".getBytes(StandardCharsets.UTF_8), info.getBytes(StandardCharsets.UTF_8))); byte[] key = new byte[32]; hkdf.generateBytes(key, 0, 32); return key; }
public ByteString eciesDecrypt(PrivateKey recipientPrivateKey, ByteString cipherText) { BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) recipientPrivateKey; ECNamedCurveSpec ecNamedCurveSpec = (ECNamedCurveSpec) bcecPrivateKey.getParams(); int level = SecurityLevel.from(ecNamedCurveSpec.getName()).size(); //cipherText = ephemeralPubKeyBytes + encryptedTokBytes + macBytes //ephemeralPubKeyBytes = first ((384+7)/8)*2 + 1 bytes = first 97 bytes //hmac is sha3_384 = 48 bytes or sha3_256 = 32 bytes int ephemeralPubKeyLength = ((level + 7) / 8) * 2 + 1; int hmacLength = level >> 3; int cipherTextLength = cipherText.size(); if (cipherTextLength <= ephemeralPubKeyLength + hmacLength) throw new RuntimeException(String.format("Illegal cipherText length: %d must be > %d", cipherTextLength, ephemeralPubKeyLength + hmacLength)); ByteString ephemeralPubKey = cipherText.substring(0, ephemeralPubKeyLength); ByteString encryptedContent = cipherText.substring(ephemeralPubKeyLength, cipherTextLength - hmacLength); ByteString hmac = cipherText.substring(cipherTextLength - hmacLength); ECPrivateKeyParameters ecdhPrivateKeyParameters; try { ecdhPrivateKeyParameters = (ECPrivateKeyParameters) (PrivateKeyFactory.createKey(bcecPrivateKey.getEncoded())); } catch (IOException e) { logger.error("ECIES decrypt load private key exception", e); throw new RuntimeException(e); } ECDomainParameters ecDomainParameters = ecdhPrivateKeyParameters.getParameters(); ECCurve ecCurve = ecDomainParameters.getCurve(); ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(ecCurve.decodePoint(ephemeralPubKey.toByteArray()), ecDomainParameters); BasicAgreement agree = new ECDHBasicAgreement(); agree.init(ecdhPrivateKeyParameters); byte[] keyAgreement = agree.calculateAgreement(ecPublicKeyParameters).toByteArray(); HKDFParameters hkdfParameters = new HKDFParameters(keyAgreement, null, null); HKDFBytesGenerator hkdfBytesGenerator = new HKDFBytesGenerator(digest); hkdfBytesGenerator.init(hkdfParameters); byte[] hkdfOutputBytes = new byte[AESKEY_LENGTH + HMACKEY_LENGTH]; hkdfBytesGenerator.generateBytes(hkdfOutputBytes, 0, AESKEY_LENGTH + HMACKEY_LENGTH); ByteString hkdfOutput = ByteString.copyFrom(hkdfOutputBytes); ByteString aesKey = hkdfOutput.substring(0, AESKEY_LENGTH); ByteString hmacKey = hkdfOutput.substring(AESKEY_LENGTH, AESKEY_LENGTH + HMACKEY_LENGTH); HMac hMac = new HMac(digest); hMac.init(new KeyParameter(hmacKey.toByteArray())); hMac.update(encryptedContent.toByteArray(), 0, encryptedContent.size()); byte[] recoveredHmac = new byte[hMac.getMacSize()]; hMac.doFinal(recoveredHmac, 0); if (!MessageDigest.isEqual(hmac.toByteArray(), recoveredHmac)) { throw new RuntimeException("HMAC verify failed"); } CFBBlockCipher aesCipher = new CFBBlockCipher( new AESEngine(), BLOCK_BIT_SIZE); ByteString iv = encryptedContent.substring(0, IV_LENGTH); CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(aesKey.toByteArray()), iv.toByteArray()); aesCipher.init(false, ivAndKey); byte[] decryptedBytes = new byte[500]; aesCipher.decryptBlock(encryptedContent.substring(IV_LENGTH).toByteArray(), 0, decryptedBytes, 0); return ByteString.copyFrom(decryptedBytes); }
/** * @param ikm * Master key * @param salt * @param info * Some extra (public) information. * @param outKeyLen * The derived key length * @return A derived key. */ public static byte[] deriveKey(byte[] ikm, byte[] salt, byte[] info, int outKeyLen) { HKDFBytesGenerator kdf = new HKDFBytesGenerator(new SHA1Digest()); kdf.init(new HKDFParameters(ikm, salt, info)); byte[] outKey = new byte[outKeyLen]; kdf.generateBytes(outKey, 0, outKeyLen); return outKey; }