Сигнатура в коде NodeJS генерируется методом jwa('ES256')#sign
, который имеет следующие функциональные возможности:
- ES256: ECDSA с использованием кривой P-256 и SHA-256 га sh алгоритм [1] .
- Подпись будет представлять собой пару (r, s), где r и s - это 256-разрядные целые числа без знака [2] .
- Сигнатура в кодировке base64url [3] .
Ad 1: соответствующая реализация для ES256 возможна в Java с использованием встроенных средств (Поставщик SunE C, Java 1,7 или выше), [4] :
Signature ecdsa = Signature.getInstance("SHA256withECDSA");
ecdsa.initSign(privateKey);
String payload = "The quick brown fox jumps over the lazy dog";
ecdsa.update(payload.getBytes(StandardCharsets.UTF_8));
byte[] signatureDER = ecdsa.sign();
Здесь privateKey
- это закрытый ключ типа java.security.PrivateKey
, аналогичный key
в коде CXF.
Объявление 2. Код Java возвращает подпись в формате ASN.1 DER и поэтому должен быть преобразован в формат (r, s) [5] . Может быть реализован пользовательский метод или метод из вспомогательной библиотеки, например, метод com.nimbusds.jose.crypto.impl.ECDSA.transcodeSignatureToConcat
из библиотеки Nimbus JOSE + JWT [6] [7] [8] :
byte[] signature = transcodeSignatureToConcat(signatureDER, 64);
Объявление 3: кодирование Base64url возможно в Java со встроенными средствами [9] :
String signatureBase64url = Base64.getUrlEncoder().withoutPadding().encodeToString(signature);
Поскольку каждый раз генерируется другая подпись, прямое сравнение подписей, сгенерированных в обоих кодах, невозможно. Однако совместимость с библиотекой jwa- npm можно проверить, проверив подпись, сгенерированную в коде Java с библиотекой jwa- npm:
const jwa = require("jwa");
const ecdsa = jwa('ES256');
var message = "The quick brown fox jumps over the lazy dog";
var verify = ecdsa.verify(message, signatureBase64url, publicKey);
Здесь signatureBase64url
- это подпись, сгенерированная с кодом Java. publicKey
- это соответствующий ключ publi c в формате PEM X.509 (-----BEGIN PUBLIC KEY-----...
) [10] .
Функциональность метода jwa('ES256')#sign
отличается от кода отправленного кода JJWT или Apache CXF: последние два генерируют JWT [11] . Заголовок - это кодировка base64url {"alg": "ES256"}
. Соответственно, подпись такова, что для кодированного заголовка Base64url и полезной нагрузки, кодированной Base64url, оба разделены точкой:
String payload = "The quick brown fox jumps over the lazy dog";
//JJWT
String jwtJJWT = Jwts.builder().setPayload(payload).signWith(io.jsonwebtoken.SignatureAlgorithm.ES256, privateKey).compact();
//CXF
JwsCompactProducer compactProducer = new JwsCompactProducer(payload);
compactProducer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.ES256);
String jwtCXF = compactProducer.signWith(privateKey);
String signatureCXF = compactProducer.getEncodedSignature(); // signature, 3. portion of JWT
Пример для JWT, сгенерированного следующим образом:
eyJhbGciOiJFUzI1NiJ9.VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw.rcrzqr3ovu7SH9ci-S6deLn6BuiQkNv9CmeOnUPwva30pfK9BOX0YOgjZP5T08wjxCBTTHV3aex0M76toL8qpw