Java tutorial
//package com.java2s; //License from project: Apache License import android.annotation.SuppressLint; import android.support.annotation.NonNull; import java.security.GeneralSecurityException; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class Main { /** * Computes an Ephemeral ID. * @param key AES key (Advertiser Identity Key). The first 16 bytes are used. * @param timeCounter Advertiser time counter * @param rotationExponent Advertiser rotation exponent (0 to 15) * @return Final ephemeral key of 16 bytes, of which only the first 8 bytes should be used. * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ @NonNull public static byte[] computeEID(byte[] key, int timeCounter, byte rotationExponent) throws GeneralSecurityException { // String transformation = "AES/CBC/PKCS5Padding"; String transformation = "AES/ECB/NoPadding"; @SuppressLint("GetInstance") // spec says it has to be ECB, ignore lint warning Cipher aes = Cipher.getInstance(transformation); aes.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, 0, 16, "AES")); byte[] tempKey = aes .doFinal(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, 0x00, 0x00, (byte) ((timeCounter >>> 24) & 0xff), (byte) ((timeCounter >>> 16) & 0xff) }); // clear K lowest bits timeCounter = timeCounter >>> rotationExponent << rotationExponent; // reset cipher with a new encryption key aes.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(tempKey, "AES")); return aes.doFinal(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, rotationExponent, (byte) ((timeCounter >>> 24) & 0xff), (byte) ((timeCounter >>> 16) & 0xff), (byte) ((timeCounter >>> 8) & 0xff), (byte) (timeCounter & 0xff) }); } }