Diff ie - Хеллман хорошо объяснен в wikipedia - и, вероятно, в некоторых из сотен вопросов, приведенных здесь, а также о crypto.SX и security.SX, но я не могу легко найти какой. Вкратце:
вы создаете пару ключей, сохраняете свой закрытый ключ и предоставляете свой открытый ключ другой стороне
другая сторона делает то же самое вещь (или ее отражение): сгенерируйте пару ключей, сохраните их закрытый ключ и предоставьте вам свой открытый ключ
вы используете свой закрытый ключ и их открытый ключ для вычисления значения «соглашения»
они аналогичным образом используют свой закрытый ключ и ваш открытый ключ для вычисления того же значение «договор». Это также называется общим секретом, потому что вы и другая сторона знаете об этом, но любой, кто подслушивает ваш трафик c, не знает.
«Предоставить» в этом синопсисе опускает много очень важных деталей. Жизненно важно, чтобы, когда вы предоставляете свой публичный ключ другой стороне, они фактически получали ваш публичный ключ, а не значение, измененное или замененное противником, и аналогично, когда они предоставляют вам свой публичный ключ, жизненно важно, чтобы вы получили настоящий, а не измененный или поддельный. Именно здесь настоящие системы ЦТ в основном выходят из строя, и тот факт, что вы не упоминаете ни о каких защитных механизмах или осложнениях, необходимых здесь, предполагает, что ваша схема будет небезопасной и легко взломанной - если она будет использована для чего-то, что стоит украсть.
Обратите внимание, что вы НИКОГДА не должны раскрывать или «посылать» свой личный ключ кому-либо, и они также не должны раскрывать свой. Это основная основа для криптографии publi c -key (или 'asymmetri c'), которая может иметь любую ценность или вообще использоваться.
Существует множество способов представления ключей, но только некоторые имеют отношение к вам.
Publi c ключи часто представлены либо в
структуре ASN.1 SubjectPublicKeyInfo определено в X.509 и более удобно в PKIX, в основном в rfc5280 # 4.1 и # 4.1.2.7 и rfc3279 2.3 , закодировано в DER , который имеет ограничение, заключающееся в том, что многие байты, используемые в этой кодировке, не являются допустимыми символами и не могут быть правильно отображены или обработаны иным образом, а иногда не переданы или даже сохранены; или
та же самая структура DER ASN.1 'завернутая' в формат 'PEM' , который преобразует проблемные двоичные данные во все отображаемые персонажи в легко управляемой форме. Формат PEM был первоначально создан для вызова схемы защищенной электронной почты Privacy Enhanced Mail , который отошел на второй план и был заменен другими схемами и технологиями, но определенный в нем формат все еще используется. Формат publickey PEM был недавно повторно стандартизирован на rfc7468 # 13 (который, как вы видите, ссылается на rfc5280).
OpenSSL поддерживает оба из них, но утилита командной строки, которую вы используете в основном , по умолчанию использует PEM - и поскольку вам нужно передать свой ключ «им» , и им необходимо передать вам свой ключ, PEM вполне может быть самым надежным и / или удобным способом сделать это. (Хотя возможны и другие форматы, если вы и они согласны - и если они требуют чего-то еще, вам придется согласиться, чтобы эта схема вообще работала.)
Java напрямую поддерживает только DER, таким образом, предполагая, что вы получили их открытый ключ в SPKI PEM, чтобы использовать его в Java, вам необходимо преобразовать его в DER. Вы можете сделать это в OpenSSL
openssl pkey -pubin -in theirpub.pem -outform der -out theirpub.der
, а затем прочитать DER в Java crypto KeyFactory:
byte[] theirpubder = Files.readAllBytes(Paths.get(whatever));
KeyFactory fact = KeyFactory.getInstance("EC");
PublicKey theirpub = fact.generatePublic(new X509EncodedKeySpec(theirpubder));
// can downcast to ECPublicKey if you want to be more specific
В качестве альтернативы вы можете Java преобразовать PEM, который не не слишком сложно; есть несколько вариантов, но мне нравится:
String theirpubpem = new String(Files.readAllBytes(Paths.get(whatever)));
// IN GENERAL letting new String(byte[]) default the charset is dangerous, but PEM is OK
byte[] theirpubder = Base64.getMIMEDecoder().decode(theirpubpem.replaceAll("-----[^\\n]*\\n","") );
// continue as for DER
Для закрытых ключей существует значительно больше представлений, но только одно (или два-i sh), которое Java разделяет с OpenSSL. Поскольку вам нужно только хранить закрытый ключ локально, а не «отправлять» его, PEM может не понадобиться; если это так, вы можете просто добавить -outform der
к своей команде pkcs8 -topk8 -nocrypt
, соответствующим образом изменив имя, и прочитать результат непосредственно в Java KeyFactory таким же образом, как указано выше, за исключением PKCS8EncodedKeySpec
и generatePrivate
и [EC]PrivateKey
. Если вы действительно хотите сохранить его в (PKCS8-clear) PEM, вы также можете комбинировать вышеуказанное. нестандартный и обычно не считается хорошей практикой, хотя для ECDH с prime256v1 (он же secp256r1 или P-256) это технически возможно. AFAIK все хорошие стандарты используют промежуточный этап получения ключа (он же Key Derivation Function или KDF). Поскольку вы не показали нам их «руководство», я не могу сказать, правильно ли это - по крайней мере, для небольших значений правильности.
Чтобы вы знали, используйте CB C с фиксированным IV более одного раза для одного и того же ключа (который в данном случае является тем же результатом DH) небезопасен. Я предполагаю, что «Тестирование» означает, что вы планируете заменить его чем-то лучшим.
Также, к вашему сведению, вам не нужно , чтобы использовать все усложнение API Cipher.init,update,doFinal
. Когда данные достаточно малы, чтобы поместиться в памяти, как здесь, вы можете просто сделать:
cipher.init(ENCRYPT_MODE, key, parms);
byte[] encrypted = cipher.doFinal (plainbytes);
// or since you want to hexify it
... bytesToHex (cipher.doFinal (plainbytes)) ...
Наконец, поскольку Java byte
подписан, ваш bytesToHex
выведет почти ровно половину всех байты с префиксом FFFFFF
. Это очень необычно и феноменально некрасиво, но, опять же, я не знаю, «правильно» ли это для вас.