Соглашение о ключе BouncyCastle ECDH не выполнено
Я реализовал криптографию Диффи-Хеллмана с использованием эллиптических кривых с использованием API BouncyCastle. Но, похоже, соглашение о ключах не работает должным образом. Это печатает ложь.
Где я сделал не так? Спасибо.
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("B-571");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDH", "BC");
g.initialize(ecSpec, new SecureRandom());
KeyPair aKeyPair = g.generateKeyPair();
KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
aKeyAgree.init(aKeyPair.getPrivate());
KeyPair bKeyPair = g.generateKeyPair();
KeyAgreement bKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
bKeyAgree.init(bKeyPair.getPrivate());
//
// agreement
//
aKeyAgree.doPhase(bKeyPair.getPublic(), true);
bKeyAgree.doPhase(aKeyPair.getPublic(), true);
byte[] aSecret = aKeyAgree.generateSecret();
byte[] bSecret = bKeyAgree.generateSecret();
System.out.println(aSecret);
System.out.println(bSecret);
if (aSecret.equals(bSecret)){
return true;
} else { return false; }
1 ответ
Это работает правильно, когда я тестировал с Bouncy Castle 1.49. Однако вы сравниваете, используя неправильный метод.
- Если вам нужно постоянное сравнение, используйте
MessageDigest.isEqual
, - Если вам не нужно сравнение с постоянным временем, используйте
Arrays.equals
,
Чтобы распечатать содержимое байтовых массивов, используйте Arrays.toString
:
System.out.println(Arrays.toString(aSecret));
System.out.println(Arrays.toString(bSecret));
return MessageDigest.isEqual(aSecret, bSecret);
Редактировать: ОП попросил меня объяснить, что означает "сравнение с постоянной времени", и вот так: сравнение с постоянной времени занимает одинаковое количество времени, независимо от того, совпадают две строки или нет. Сравнение без постоянной времени обычно выполняется быстрее, если две строки имеют несоответствие, а время выполнения зависит от того, где находится несоответствие: сравнение останавливается, когда обнаруживается первое несоответствие.
Нужно ли вам сравнение с постоянным временем или нет, зависит от того, есть ли у вас оракул времени. То есть время, затраченное на сравнение, даст злоумышленнику полезную информацию?
Вот пример временного оракула: предположим, что вы веб-сервер, отправляющий куки в браузер. Вы не хотите, чтобы пользователь вмешивался в cookie, поэтому вы присоединяете HMAC к содержимому cookie:
cookie_to_send = hmac(cookie) + ":" + cookie
Теперь, когда браузер отправляет вам файл cookie, вы заново вычисляете HMAC и смотрите, соответствует ли он:
mac, cookie = received_cookie.split(":")
compare(mac, hmac(cookie))
И если сравнение не удается (mac
не соответствует hmac(cookie)
), тогда вы отклоните запрос.
В этом compare
Операция выше, очень, очень важно, чтобы это было сравнение с постоянным временем. В противном случае злоумышленник может посмотреть, сколько времени понадобилось вашему серверу, чтобы отклонить запрос, и использовать его, чтобы определить ожидаемое значение HMAC. Это потому, что один компонент сравнения (значение HMAC в cookie, перед первым :
) контролируется злоумышленником, и злоумышленник может корректировать его значение побайтно, чтобы увидеть, сколько времени занимает отклонение каждый раз.
В вашем случае ваши байтовые массивы (которые вы сравниваете) генерируются из generateSecret()
, что говорит мне о том, что он не контролируется злоумышленниками. Таким образом, на первый взгляд, это не выглядит так, как будто необходимо постоянное сравнение. Но я не эксперт по безопасности, поэтому точно не знаю. Всегда безопасно (но может быть медленным, если сравниваемые строки длинные) использовать сравнение с постоянной времени, поэтому, если вообще не уверены, это то, что я предлагаю.