Создание секретных ключей с одинаковым общим секретом приводит к разным результатам. - PullRequest
0 голосов
/ 23 мая 2019

Я работаю над приложением Android, которое требует создания безопасного канала между приложением и сервером (.NET), первый шаг - создание общего секрета, приложение генерирует пару ключей (EC) и отправляет открытый ключ затем сервер создает свою собственную пару ключей и отправляет открытый ключ в приложение и сохраняет общий секрет, созданный на основе открытых и закрытых ключей приложения, а сервер отправляет обратно приложению свой собственный открытый, солевой и iv, затем приложение выполняет соглашение о ключах, в результате и приложение для Android, и сервер имеют строку, созданную на основе открытых и закрытых ключей.

Позже, когда приложение для Android хочет отправить зашифрованное сообщение на сервер, я беру сгенерированный секрет, соль и iv и создаю секретный ключ, чтобы иметь возможность использовать Cipher для шифрования сообщения.

Проблема в том, что даже если приложение и сервер имеют один и тот же секрет секрета, salt и iv, по какой-то причине android генерирует SecretKey, отличный от сервера (мы проверили в режиме отладки, чтобы увидеть, что разделяемый секрет salt и iv такие же).

Вот код, который я использую для создания секретного ключа:

byte[] sharedSecretBytes = Base64.decode(sharedSecretBase64, Base64.DEFAULT);
byte[] ivBytes = Base64.decode(ivBase64, Base64.DEFAULT);
byte[] saltBytes = Base64.decode(saltBase64, Base64.DEFAULT);


String sharedSecret = new String(sharedSecretBytes, "UTF-8");
//i tried to use different encoding, no luck.
//String sharedSecretAscii = new String(sharedSecretBytes, "ASCII");
char[] charArray  = sharedSecret .toCharArray();

PBEKeySpec keySpec = new PBEKeySpec(charArray, saltBytes, 1000, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);

//here the keyBytes are not the same as generated in the server.
byte[] keyBytes = key.getEncoded();

//i saw in some tutorial somene do this, not sure why because we can provide the key as is to the cipher, 
//the problem is that both not working.
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), "AES");


IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

byte[] encrypted = cipher.doFinal(logNumber.getBytes("UTF-8"));
String asString = Base64.encodeToString(encrypted, Base64.NO_WRAP);

Я также попытался опубликовать жестко запрограммированный общий секретный ключ как «123abc» как на Android, так и на стороне сервера, и на самом деле это сработало, поэтому я предполагаю, что проблема заключается в преобразовании sharedSecrte.toCharArray(), если sharedSecret содержит странные символы может привести к генерации Java плохой секретный ключ?

Также мы работаем над приложением для iOS, которое выполняет точно такой же процесс и не имеет проблем с генерацией правильных ключей.

1 Ответ

0 голосов
/ 28 мая 2019

В конце концов, единственное, что сработало, как ожидалось, это использование библиотеки Bouncy Castle Что я сделал, это:

PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
      generator.init(sharedSecretBytes, saltBytes, 1000);
      byte[] dk = ((KeyParameter) generator.generateDerivedParameters(256)).getKey();
      SecretKeySpec secretKeySpec = new SecretKeySpec(dk, "AES");


      IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

      byte[] encrypted = cipher.doFinal(logNumber.getBytes("UTF-8"));

Все еще не понимаю, почему нативный java.security создает проблемы.

...