Я пытаюсь реализовать шифрование / дешифрование ECDH вместе с JWE в Android (Java).
Я нашел библиотеки jose4j и Nimbus JOSE , которые нацелены на то, чтобы делать все, что мне нужно, но оказалось, что это сложнее, чем я думал.
Если кто-то знаком, тогда это для 3D Secure 2.0 ...
В спецификации ниже:
- SDK = местная сторона
- DS = Сервер каталогов (сторона другая )
Следующая спецификация:
- Дано: P (DS) - открытый ключ EC (предоставляется в формате PEM, может быть преобразован в PublicKey или в JWK)
- Создание новой пары эфемерных ключей (Q (SDK), d (SDK))
- Проведите процесс обмена ключами Диффи-Хеллмана в соответствии с JWA (RFC7518) в режиме прямого соглашения о ключах, используя кривые P-256, d (SDK) и P (DS) для получения CEK. Значения параметров, поддерживаемые в этой версии спецификации:
- "ALG": ECDH-ES
- "APV": DirectoryServerID
- "epk": P (DS), формат inJSONWebKey (JWK) {"kty": "EC", "crv": "P-256"}
- Все остальные параметры: отсутствуют
- СЕК: "KTY": окт-256bits
- Генерация 128-битных случайных данных как IV
- Шифрование объекта JSON в соответствии с JWE (RFC7516) с использованием компактной сериализации CEK и JWE. Значения параметров, поддерживаемые в этой версии спецификации:
- "ALG": каталог
- "epk": Q (SDK) as {"kty": "EC", "crv": "P-256"}
- "ENC": либо "A128CBC-HS256" или "A128GCM"
- Все остальные параметры: отсутствуют
- Если используется алгоритм A128CBC-HS256, используйте полный CEK или если алгоритм A128GCM, используйте крайние левые 128 бит CEK.
- Удалить пару эфемерных ключей (Q (SDK), d (SDK))
- Делает полученный JWE доступным для сервера 3DS как зашифрованные данные SDK
Если бы кто-то реализовал эту точную спецификацию и смог поделиться кодом, это было бы замечательно !!
В примерах jose4j приведен пример создания JWT с использованием ECDH:
https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples (последний пример, озаглавленный «Создание и использование вложенного (подписанного и зашифрованного) JWT»).
Но этот пример не совсем то, что мне нужно. Он создает токен, а мне нужно зашифровать текст.
Начиная с "CEK:" kty ": oct-256bits" в спецификации выше, я не понимаю, что делать.
Вот мой код (пока что) с использованием Nimbus lib:
public String nimbus_encrypt(String plainJson, ECPublicKey otherPublicKey, String directoryServerId) throws JOSEException {
JWEHeader jweHeader = new JWEHeader(
JWEAlgorithm.ECDH_ES,
EncryptionMethod.A128CBC_HS256,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
Base64URL.encode(directoryServerId),
null,
0,
null,
null,
null,
null);
JWEObject jwe = new JWEObject(jweHeader, new Payload(plainJson));
jwe.encrypt(new ECDHEncrypter(otherPublicKey));
String serializedJwe = jwe.serialize();
Log.d("[ENCRYPTION]", "nimbus_encrypt: jwe = " + jwe.getHeader());
Log.d("[ENCRYPTION]", "nimbus_encrypt: serializedJwe = " + serializedJwe);
return serializedJwe;
}
Это вывод нимба:
nimbus_encrypt: jwe = {"epk": {"kty": "EC", "crv": "P-256", "x": "AS0GRfAOWIDONXxaPR_4IuNHcDIUJPHbACjG5L7x-nQ", "ywFN6-ФУНТ-1):" ywFN6 mh1NYw "}," APV ":" RjAwMDAwMDAwMQ», "ENC": "A128CBC-HS256", "ALG": "ECDH-ES"} * 1 086 *
nimbus_encrypt: serializedJwe = eyJlcGsiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJBUzBHUmZBT1dJRE9OWHhhUFJfNEl1TkhjRElVSlBIYkFDakc1TDd4LW5RIiwieSI6InhvbkZuMXZSQVNLVVRkQ2tGVHdzbDE2TFJtU2UtYkFGOEVPNC1taDFOWXcifSwiYXB2IjoiUmpBd01EQXdNREF3TVEiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiRUNESC1FUyJ9..Pi48b7uj3UilvVXKewFacg.0sx9OkHxxtZvkVm-IENRFw.bu5GvOAwcZxdxaDKWIBqwA
Вот мой код (пока, используя ответ @ Brian-Campbell), используя jose4j lib:
public String jose4j_encrypt(String plainJson, PublicKey otherPublicKey, String directoryServerId) throws JoseException {
JsonWebEncryption jwe = new JsonWebEncryption();
jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.ECDH_ES);
jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256);
jwe.setHeader(HeaderParameterNames.AGREEMENT_PARTY_V_INFO, Base64Url.encodeUtf8ByteRepresentation(directoryServerId));
jwe.setKey(otherPublicKey);
jwe.setPayload(plainJson);
String serializedJwe = jwe.getCompactSerialization();
Log.d("[ENCRYPTION]", "jose4j_encrypt: jwe = " + jwe);
Log.d("[ENCRYPTION]", "jose4j_encrypt: serializedJwe = " + serializedJwe);
return serializedJwe;
}
Это вывод jose4j:
jose4j_encrypt: jwe = JsonWebEncryption {"alg": "ECDH-ES", "enc": "A128CBC-HS256", "apv": "RjAwMDAwMDAwMQ", "epk": {"kty": "EC", "х": "prvyhexJXDWvPQmPA1xBjY8mkHEbrEiJ4Dr-7_5YfdQ", "у": "fPjw8UdfzgkVTppPSN5o_wprItKLwecoia9yrWi38yo", "CRV": "Р-256"}} * +1097 *
jose4j_encrypt: serializedJwe = eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImFwdiI6IlJqQXdNREF3TURBd01RIiwiZXBrIjp7Imt0eSI6IkVDIiwieCI6InBydnloZXhKWERXdlBRbVBBMXhCalk4bWtIRWJyRWlKNERyLTdfNVlmZFEiLCJ5IjoiZlBqdzhVZGZ6Z2tWVHBwUFNONW9fd3BySXRLTHdlY29pYTl5cldpMzh5byIsImNydiI6IlAtMjU2In19..gxWYwFQSOqLk5HAgs7acdA.mUIHBiWpWSlQaEOJ_EZGYA.eiTe-88fw-Jfuhji_W0rtg
Как видно, заголовок «alg» в конечном результате - «ECDH-ES», а не «dir», как требуется.
Если бы я реализовал обе стороны связи, то этого было бы достаточно, но с этой спецификацией кажется, что многие конфигурации здесь отсутствуют ...
Код, использующий jose4j, длиннее и кажется более настраиваемым, но я не смог создать что-то достаточно ценное для публикации здесь.
Основная недостающая часть для меня - это как генерировать CEK из приведенной выше спецификации.
Спасибо.
EDIT
Добавлен код jose4j выше и добавлены выходные данные ...