/** * Test public key encryption. * * @throws Exception When test fails. */ @Test public void testActivationGenerate() throws Exception { String activationOTP = "CKZ2O-OE544"; String activationIdShort = "IFA6F-3NPAZ"; byte[] activationNonce = BaseEncoding.base64().decode("grDwkvXrgfUdKBsqg0xYYw=="); byte[] publicKeyBytes = BaseEncoding.base64() .decode( "BJXfJMCANX+T9FzsG6Hi0KTYPN64i7HxMiWoMYPd17DYfBR+IwzOesTh/jj/B3trL9m3O1oODYil+8ssJzDt/QA="); byte[] ephemeralPrivateKeyBytes = BaseEncoding.base64().decode("AKeMTtivK/XRiQPhfJYxAw1L62ah4lGTQ4JKqRrr0fnC"); byte[] masterPublicKey = BaseEncoding.base64() .decode( "BFOqvpLNi15eHDt8fkFxFe034Buw/i8gR3ax4fKiIQynt5K858oBBYhqLVH8FhNmMnlysnRd2UsPJSQxzoPhEn8="); CryptoProviderUtil keyConvertor = PowerAuthConfiguration.INSTANCE.getKeyConvertor(); PrivateKey eph = keyConvertor.convertBytesToPrivateKey(ephemeralPrivateKeyBytes); PublicKey mpk = keyConvertor.convertBytesToPublicKey(masterPublicKey); PublicKey publicKey = PowerAuthConfiguration.INSTANCE.getKeyConvertor().convertBytesToPublicKey(publicKeyBytes); PowerAuthClientActivation activation = new PowerAuthClientActivation(); byte[] cDevicePublicKey = activation.encryptDevicePublicKey( publicKey, eph, mpk, activationOTP, activationIdShort, activationNonce); assertArrayEquals( cDevicePublicKey, BaseEncoding.base64() .decode( "tnAyB0C5I9xblLlFCPONUT4GtABvutPkRvvx2oTeGIuUMAmUYTqJluKn/Zge+vbq+VArIVNYVTd+0yuBZGVtkkd1mTcc2eTDhqZSQJS6mMgmKeCqv64c6E4dm4INOkxh")); }
/** Add crypto providers. */ @Before public void setUp() { // Add Bouncy Castle Security Provider Security.addProvider(new BouncyCastleProvider()); PowerAuthConfiguration.INSTANCE.setKeyConvertor( CryptoProviderUtilFactory.getCryptoProviderUtils()); }
/** * Decrypt the device public key using activation OTP. * * @param C_devicePublicKey Encrypted device public key. * @param activationIdShort Short activation ID. * @param activationOTP Activation OTP value. * @param activationNonce Activation nonce, used as an initialization vector for AES encryption. * @return A decrypted public key. */ public PublicKey decryptDevicePublicKey( byte[] C_devicePublicKey, String activationIdShort, String activationOTP, byte[] activationNonce) { try { // Derive longer key from short activation ID and activation OTP byte[] activationIdShortBytes = activationIdShort.getBytes("UTF-8"); SecretKey otpBasedSymmetricKey = new KeyGenerator().deriveSecretKeyFromPassword(activationOTP, activationIdShortBytes); // Decrypt device public key AESEncryptionUtils aes = new AESEncryptionUtils(); byte[] decryptedPublicKeyBytes = aes.decrypt(C_devicePublicKey, activationNonce, otpBasedSymmetricKey); PublicKey devicePublicKey = PowerAuthConfiguration.INSTANCE .getKeyConvertor() .convertBytesToPublicKey(decryptedPublicKeyBytes); return devicePublicKey; } catch (IllegalBlockSizeException | InvalidKeySpecException | BadPaddingException | InvalidKeyException | UnsupportedEncodingException ex) { Logger.getLogger(PowerAuthServerActivation.class.getName()).log(Level.SEVERE, null, ex); } return null; }
/** * Test that the keys are correctly generated. * * @throws Exception When test fails. */ @Test public void testGenerateKeys() throws Exception { CryptoProviderUtil keyConvertor = PowerAuthConfiguration.INSTANCE.getKeyConvertor(); KeyGenerator keyGenerator = new KeyGenerator(); KeyPair kp = keyGenerator.generateKeyPair(); System.out.println( "Private Key: " + BaseEncoding.base64().encode(keyConvertor.convertPrivateKeyToBytes(kp.getPrivate()))); System.out.println( "Public Key: " + BaseEncoding.base64().encode(keyConvertor.convertPublicKeyToBytes(kp.getPublic()))); }
/** * Compute a fingerprint of the device public key. The fingerprint can be used for visual * validation of an exchanged public key. * * @param devicePublicKey Public key for computing fingerprint. * @return Fingerprint of the public key. */ public int computeDevicePublicKeyFingerprint(PublicKey devicePublicKey) { try { byte[] devicePublicKeyBytes = PowerAuthConfiguration.INSTANCE .getKeyConvertor() .convertPublicKeyToBytes(devicePublicKey); MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(devicePublicKeyBytes); if (hash.length < 4) { // assert throw new IndexOutOfBoundsException(); } int index = hash.length - 4; int number = (ByteBuffer.wrap(hash).getInt(index) & 0x7FFFFFFF) % (int) (Math.pow(10, PowerAuthConfiguration.FINGERPRINT_LENGTH)); return number; } catch (NoSuchAlgorithmException ex) { Logger.getLogger(PowerAuthServerActivation.class.getName()).log(Level.SEVERE, null, ex); } return 0; }
/** * 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; }