/** * Encrypt the server public key using activation OTP and device public key. As a technical * component for public key encryption, an ephemeral private key is used (in order to deduce * ephemeral symmetric key using ECDH). * * @param serverPublicKey Server public key to be encrypted. * @param devicePublicKey Device public key used for encryption. * @param ephemeralPrivateKey Ephemeral private key. * @param activationOTP Activation OTP value. * @param activationIdShort Short activation ID. * @param activationNonce Activation nonce, used as an initialization vector for AES encryption. * @return Encrypted server public key. * @throws InvalidKeyException In case some of the provided keys is invalid. */ public byte[] encryptServerPublicKey( PublicKey serverPublicKey, PublicKey devicePublicKey, PrivateKey ephemeralPrivateKey, String activationOTP, String activationIdShort, byte[] activationNonce) throws InvalidKeyException { try { // Convert public key to bytes byte[] serverPublicKeyBytes = PowerAuthConfiguration.INSTANCE .getKeyConvertor() .convertPublicKeyToBytes(serverPublicKey); // Generate symmetric keys KeyGenerator keyGenerator = new KeyGenerator(); SecretKey ephemeralSymmetricKey = keyGenerator.computeSharedKey(ephemeralPrivateKey, devicePublicKey); byte[] activationIdShortBytes = activationIdShort.getBytes("UTF-8"); SecretKey otpBasedSymmetricKey = keyGenerator.deriveSecretKeyFromPassword(activationOTP, activationIdShortBytes); // Encrypt the data AESEncryptionUtils aes = new AESEncryptionUtils(); byte[] encryptedTMP = aes.encrypt(serverPublicKeyBytes, activationNonce, otpBasedSymmetricKey); byte[] encryptServerPublicKey = aes.encrypt(encryptedTMP, activationNonce, ephemeralSymmetricKey); return encryptServerPublicKey; } catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException ex) { Logger.getLogger(PowerAuthServerActivation.class.getName()).log(Level.SEVERE, null, ex); } return null; }
/** * Test of the complete activation process, orchestration between client and server. * * @throws Exception In case test fails */ @Test public void testActivationProcess() throws Exception { System.out.println("TEST: Activation Process"); // Prepare test data KeyGenerator keyGenerator = new KeyGenerator(); PowerAuthClientActivation clientActivation = new PowerAuthClientActivation(); PowerAuthServerActivation serverActivation = new PowerAuthServerActivation(); KeyPair masterKeyPair = keyGenerator.generateKeyPair(); // Generate master keypair PrivateKey masterPrivateKey = masterKeyPair.getPrivate(); PublicKey masterPublicKey = masterKeyPair.getPublic(); for (int i = 0; i < 20; i++) { // SERVER: Generate data for activation String activationId = serverActivation.generateActivationId(); String activationIdShort = serverActivation.generateActivationIdShort(); String activationOTP = serverActivation.generateActivationOTP(); byte[] activationSignature = serverActivation.generateActivationSignature( activationIdShort, activationOTP, masterPrivateKey); KeyPair serverKeyPair = serverActivation.generateServerKeyPair(); PrivateKey serverPrivateKey = serverKeyPair.getPrivate(); PublicKey serverPublicKey = serverKeyPair.getPublic(); // CLIENT: Verify activation signature boolean activationSignatureOK = clientActivation.verifyActivationDataSignature( activationIdShort, activationOTP, activationSignature, masterPublicKey); assertTrue(activationSignatureOK); // CLIENT: Generate and send public key KeyPair deviceKeyPair = clientActivation.generateDeviceKeyPair(); KeyPair clientEphemeralKeyPair = keyGenerator.generateKeyPair(); PrivateKey devicePrivateKey = deviceKeyPair.getPrivate(); PublicKey devicePublicKey = deviceKeyPair.getPublic(); byte[] clientNonce = clientActivation.generateActivationNonce(); byte[] c_devicePublicKey = clientActivation.encryptDevicePublicKey( devicePublicKey, clientEphemeralKeyPair.getPrivate(), masterPublicKey, activationOTP, activationIdShort, clientNonce); // SERVER: Decrypt device public key PublicKey decryptedDevicePublicKey = serverActivation.decryptDevicePublicKey( c_devicePublicKey, activationIdShort, masterPrivateKey, clientEphemeralKeyPair.getPublic(), activationOTP, clientNonce); assertEquals(devicePublicKey, decryptedDevicePublicKey); // SERVER: Encrypt and send encrypted server public and it's signature KeyPair ephemeralKeyPair = keyGenerator.generateKeyPair(); PrivateKey ephemeralPrivateKey = ephemeralKeyPair.getPrivate(); PublicKey ephemeralPublicKey = ephemeralKeyPair.getPublic(); byte[] serverNonce = serverActivation.generateActivationNonce(); byte[] c_serverPublicKey = serverActivation.encryptServerPublicKey( serverPublicKey, devicePublicKey, ephemeralPrivateKey, activationOTP, activationIdShort, serverNonce); byte[] c_serverPublicKeySignature = serverActivation.computeServerDataSignature( activationId, c_serverPublicKey, masterPrivateKey); // CLIENT: Validate server public key signature and decrypt server public key boolean serverPublicKeySignatureOK = clientActivation.verifyServerDataSignature( activationId, c_serverPublicKey, c_serverPublicKeySignature, masterPublicKey); assertTrue(serverPublicKeySignatureOK); PublicKey decryptedServerPublicKey = clientActivation.decryptServerPublicKey( c_serverPublicKey, devicePrivateKey, ephemeralPublicKey, activationOTP, activationIdShort, serverNonce); assertEquals(serverPublicKey, decryptedServerPublicKey); // CLIENT and SERVER: Compute device public key fingerprint int devicePublicKeyFingerprintClient = clientActivation.computeDevicePublicKeyFingerprint(devicePublicKey); int devicePublicKeyFingerprintServer = serverActivation.computeDevicePublicKeyFingerprint(decryptedDevicePublicKey); assertEquals(devicePublicKeyFingerprintClient, devicePublicKeyFingerprintServer); // CLIENT and SERVER: Compute shared master secret SecretKey sharedMasterSecretDevice = keyGenerator.computeSharedKey(devicePrivateKey, serverPublicKey); SecretKey sharedMasterSecretServer = keyGenerator.computeSharedKey(serverPrivateKey, devicePublicKey); assertEquals(sharedMasterSecretDevice, sharedMasterSecretServer); } }