All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dromara.hutool.json.jwt.signers.EllipticCurveJWTSigner Maven / Gradle / Ivy

There is a newer version: 6.0.0.M3
Show newest version
/*
 * Copyright (c) 2013-2024 Hutool Team and hutool.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.dromara.hutool.json.jwt.signers;

import org.dromara.hutool.json.jwt.JWTException;

import java.security.Key;
import java.security.KeyPair;

/**
 * 椭圆曲线(Elliptic Curve)的JWT签名器。
* 按照https://datatracker.ietf.org/doc/html/rfc7518#section-3.4,
* Elliptic Curve Digital Signature Algorithm (ECDSA)算法签名需要转换DER格式为pair (R, S) * * @author looly * @since 5.8.21 */ public class EllipticCurveJWTSigner extends AsymmetricJWTSigner { /** * 构造 * * @param algorithm 算法 * @param key 密钥 */ public EllipticCurveJWTSigner(final String algorithm, final Key key) { super(algorithm, key); } /** * 构造 * * @param algorithm 算法 * @param keyPair 密钥对 */ public EllipticCurveJWTSigner(final String algorithm, final KeyPair keyPair) { super(algorithm, keyPair); } @Override protected byte[] sign(final byte[] data) { // https://datatracker.ietf.org/doc/html/rfc7518#section-3.4 return derToConcat(super.sign(data), getSignatureByteArrayLength(getAlgorithm())); } @Override protected boolean verify(final byte[] data, final byte[] signed) { // https://datatracker.ietf.org/doc/html/rfc7518#section-3.4 return super.verify(data, concatToDER(signed)); } /** * 获取签名长度 * * @param alg 算法 * @return 长度 * @throws JWTException JWT异常 */ private static int getSignatureByteArrayLength(final String alg) throws JWTException { switch (alg) { case "ES256": case "SHA256withECDSA": return 64; case "ES384": case "SHA384withECDSA": return 96; case "ES512": case "SHA512withECDSA": return 132; default: throw new JWTException("Unsupported Algorithm: {}", alg); } } /** * DER格式转换为pair (R, S) * * @param derSignature DER格式签名 * @param outputLength 算法签名长度 * @return pair (R, S) * @throws JWTException JWT异常 */ private static byte[] derToConcat(final byte[] derSignature, final int outputLength) throws JWTException { if (derSignature.length < 8 || derSignature[0] != 48) { throw new JWTException("Invalid ECDSA signature format"); } final int offset; if (derSignature[1] > 0) { offset = 2; } else if (derSignature[1] == (byte) 0x81) { offset = 3; } else { throw new JWTException("Invalid ECDSA signature format"); } final byte rLength = derSignature[offset + 1]; int i = rLength; while ((i > 0) && (derSignature[(offset + 2 + rLength) - i] == 0)) { i--; } final byte sLength = derSignature[offset + 2 + rLength + 1]; int j = sLength; while ((j > 0) && (derSignature[(offset + 2 + rLength + 2 + sLength) - j] == 0)) { j--; } int rawLen = Math.max(i, j); rawLen = Math.max(rawLen, outputLength / 2); if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset || (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength || derSignature[offset] != 2 || derSignature[offset + 2 + rLength] != 2) { throw new JWTException("Invalid ECDSA signature format"); } final byte[] concatSignature = new byte[2 * rawLen]; System.arraycopy(derSignature, (offset + 2 + rLength) - i, concatSignature, rawLen - i, i); System.arraycopy(derSignature, (offset + 2 + rLength + 2 + sLength) - j, concatSignature, 2 * rawLen - j, j); return concatSignature; } /** * pair (R, S)转换为DER格式 * * @param jwsSignature JWT签名 * @return DER格式签名 */ private static byte[] concatToDER(final byte[] jwsSignature) { final int rawLen = jwsSignature.length / 2; int i = rawLen; while ((i > 0) && (jwsSignature[rawLen - i] == 0)) { i--; } int j = i; if (jwsSignature[rawLen - i] < 0) { j += 1; } int k = rawLen; while ((k > 0) && (jwsSignature[2 * rawLen - k] == 0)) { k--; } int l = k; if (jwsSignature[2 * rawLen - k] < 0) { l += 1; } final int len = 2 + j + 2 + l; if (len > 255) { throw new JWTException("Invalid ECDSA signature format"); } int offset; final byte[] derSignature; if (len < 128) { derSignature = new byte[2 + 2 + j + 2 + l]; offset = 1; } else { derSignature = new byte[3 + 2 + j + 2 + l]; derSignature[1] = (byte) 0x81; offset = 2; } derSignature[0] = 48; derSignature[offset++] = (byte) len; derSignature[offset++] = 2; derSignature[offset++] = (byte) j; System.arraycopy(jwsSignature, rawLen - i, derSignature, (offset + j) - i, i); offset += j; derSignature[offset++] = 2; derSignature[offset++] = (byte) l; System.arraycopy(jwsSignature, 2 * rawLen - k, derSignature, (offset + l) - k, k); return derSignature; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy