@Override public void generateAndVerifySessionKey( ECPublicKey client_ephemeral_key, byte[] kdf_data, byte[] attestation_arguments, X509Certificate device_certificate, byte[] session_attestation) throws IOException { try { // SP800-56A C(2, 0, ECC CDH) KeyAgreement key_agreement = KeyAgreement.getInstance("ECDH"); key_agreement.init(server_ec_private_key); key_agreement.doPhase(client_ephemeral_key, true); byte[] Z = key_agreement.generateSecret(); // The custom KDF Mac mac = Mac.getInstance(MACAlgorithms.HMAC_SHA256.getJCEName()); mac.init(new SecretKeySpec(Z, "RAW")); session_key = mac.doFinal(kdf_data); if (device_certificate == null) { // Privacy enabled mode mac = Mac.getInstance(MACAlgorithms.HMAC_SHA256.getJCEName()); mac.init(new SecretKeySpec(session_key, "RAW")); byte[] session_key_attest = mac.doFinal(attestation_arguments); // Verify that the session key signature is correct if (!ArrayUtil.compare(session_key_attest, session_attestation)) { throw new IOException("Verify attestation failed"); } } else { // E2ES mode PublicKey device_public_key = device_certificate.getPublicKey(); // Verify that attestation was signed by the device key if (!new SignatureWrapper( device_public_key instanceof RSAPublicKey ? AsymSignatureAlgorithms.RSA_SHA256 : AsymSignatureAlgorithms.ECDSA_SHA256, device_public_key) .update(attestation_arguments) .verify(session_attestation)) { throw new IOException("Verify provisioning signature failed"); } } } catch (GeneralSecurityException e) { throw new IOException(e); } }
@Override public byte[] mac(byte[] data, byte[] key_modifier) throws IOException { try { Mac mac = Mac.getInstance(MACAlgorithms.HMAC_SHA256.getJCEName()); mac.init(new SecretKeySpec(ArrayUtil.add(session_key, key_modifier), "RAW")); return mac.doFinal(data); } catch (GeneralSecurityException e) { throw new IOException(e); } }