使用 Apereo CAS 发布的 net core 加密 JWT 解码
Decode with net core encrypted JWT issued by Apereo CAS
Apereo CAS 单点登录发布了以下 JWT。
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.ZXlKNmFYQWlPaUpFUlVZaUxDSmhiR2NpT2lKa2FYSWlMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySWl3aWRIbHdJam9pU2xkVUluMC4uREJXMFNUa19OSUVrMmFCVElJNHVnUS5qX3l4a1BVOHNzQ2tCUkdrdjN2RGI0QjFyVDRHWEhzRUJtTlJvTVR0d0hvMjc0NF96cHIzaW1JUk15ek1nU0RIcF9xcXFIQVVnNUNvM3JuM0FTQWUzS1VaMmFsR1B1SmIzT3UxN0hGR2t6a0RDS29CamdHdU9LVHowMlpfVWpYcm1hZXg0RDVyOUt1blNZYWxTWVBDTFU3TncyZEZVWHBwWnlrb3pQdXl6RFFadjZVMDlQaXgxa1gtLW9obUpFVUZJWlN6Vi1DQUs1RTRsSmtWU3ZrZ1gxSmVBMkVjNlY4aFJUSzFIMXRmb2t6Y09nNlJXNElWN05JNVJUQW8ycmlIVlVnLV94czZIY2JFcFZxR0hlVW5QNmF0Nl9zLTFnbGMzTTFzeHBJcmxBN3FEblhPUGt1ZjFmbnpwcEpFVmZWVTV2LWpOUDZQQ0ZnMjA2S2pjeDBYYlRVX0hWN1NyUUhyWUx2Y0gwVWlWVjljZGNOWmJ0Q2hjQjkwX2M2YXVRVmZjeEJZZjE1c2V0M2g3MzA0T0w5RmM5MG5fbXNyV3RIMnVYcGxfUEEwc29IMnJMM0xVV3YyS1E0WE5lR0V5eXpqRXBZWTU3VzJMazZreWQ2UU13RV9ndy5TenQ3WGFqbTBnSy11bk05djl5azdB.V50nzzET85j2FAMRGCLqN1sLXZ8WZrfH0G5__WL6UwvrjAZbvj9tjXAnwcIoBeyFU-zvIsjom520-p2JCNoqEg
我知道它是使用 JWE standard 加密的 JWT。加密密钥如下。
9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8
签名密码如下。
9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8
用于正确解码此 JWT 的 java 代码如下。
public Assertion validate(String ticket) throws TicketValidationException {
try {
System.out.println("ticket="+ticket);
final Key key = new AesKey(signingKey.getBytes(StandardCharsets.UTF_8));
final JsonWebSignature jws = new JsonWebSignature();
jws.setCompactSerialization(ticket);
jws.setKey(key);
if (!jws.verifySignature()) {
throw new TicketValidationException("JWT verification failed");
}
final byte[] decodedBytes = Base64.decodeBase64(jws.getEncodedPayload().getBytes(StandardCharsets.UTF_8));
final String decodedPayload = new String(decodedBytes, StandardCharsets.UTF_8);
final JsonWebEncryption jwe = new JsonWebEncryption();
final JsonWebKey jsonWebKey = JsonWebKey.Factory
.newJwk("\n" + "{\"kty\":\"oct\",\n" + " \"k\":\"" + encryptionKey + "\"\n" + "}");
jwe.setCompactSerialization(decodedPayload);
jwe.setKey(new AesKey(jsonWebKey.getKey().getEncoded()));
System.out.println("JWT ---> "+jwe.getPlaintextString());
JSONParser parser = new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE);
JSONObject json = (JSONObject) parser.parse(jwe.getPlaintextString());
return new AssertionImpl(json.getAsString("sub"));
} catch (JoseException | TicketValidationException ex) {
logger.error(Arrays.toString(ex.getStackTrace()));
} catch (ParseException ex) {
java.util.logging.Logger.getLogger(CustomJWTValidator.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
我正在尝试在 net core 2.2 中解码相同的 JWT。代码如下
var encryptionKey = "9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8";
var jsonWebKey = "\n" + "{\"kty\":\"oct\",\n" + " \"k\":\"" + encryptionKey + "\"\n" + "}";
var jwkc = new JsonWebKey(jsonWebKey);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8")),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
TokenDecryptionKey = jwkc,
};
});
我故意禁用了签名验证和任何其他类型的验证。然而,在 JWT 验证中,我有以下错误。
System.ArgumentException: IDX12723: Unable to decode the payload 'ZXlKNmF...5azdB' as Base64Url encoded string. jwtEncodedString: ''. ---> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: e. Path '', line 0, position 0.
负载似乎没有被正确解码。到目前为止,很多谷歌搜索都没有给我任何结果。
我能够完全加载、验证签名和解密令牌。
问题来自您收到的密钥:当签名密钥不是时,加密密钥已经是 base64url 安全编码。
对应的JWK为(分别为签名和加密):
{"kty":"oct","k":"OU8yMlZkN1FKdTNtQk5oT3k4dndaYVNIMVVQZGllV0FqNGY5c2kycS1PODlPMjJWZDdRSnUzbUJOaE95OHZ3WmFTSDFVUGRpZVdBajRmOXNpMnEtTzg"}
和
{"kty":"oct","k":"9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8"}
编辑:作为记录,我使用了 web-token/jwt-framework(PHP 库)和以下脚本:
<?php
use Base64Url\Base64Url;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;
use Jose\Component\Encryption\Algorithm\KeyEncryption\Dir;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEDecrypter;
use Jose\Component\Encryption\Serializer\CompactSerializer as JweSerializer;
use Jose\Component\Signature\Algorithm\HS512;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\CompactSerializer as JwsSerializer;
require_once 'vendor/autoload.php';
$token = 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.ZXlKNmFYQWlPaUpFUlVZaUxDSmhiR2NpT2lKa2FYSWlMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySWl3aWRIbHdJam9pU2xkVUluMC4uREJXMFNUa19OSUVrMmFCVElJNHVnUS5qX3l4a1BVOHNzQ2tCUkdrdjN2RGI0QjFyVDRHWEhzRUJtTlJvTVR0d0hvMjc0NF96cHIzaW1JUk15ek1nU0RIcF9xcXFIQVVnNUNvM3JuM0FTQWUzS1VaMmFsR1B1SmIzT3UxN0hGR2t6a0RDS29CamdHdU9LVHowMlpfVWpYcm1hZXg0RDVyOUt1blNZYWxTWVBDTFU3TncyZEZVWHBwWnlrb3pQdXl6RFFadjZVMDlQaXgxa1gtLW9obUpFVUZJWlN6Vi1DQUs1RTRsSmtWU3ZrZ1gxSmVBMkVjNlY4aFJUSzFIMXRmb2t6Y09nNlJXNElWN05JNVJUQW8ycmlIVlVnLV94czZIY2JFcFZxR0hlVW5QNmF0Nl9zLTFnbGMzTTFzeHBJcmxBN3FEblhPUGt1ZjFmbnpwcEpFVmZWVTV2LWpOUDZQQ0ZnMjA2S2pjeDBYYlRVX0hWN1NyUUhyWUx2Y0gwVWlWVjljZGNOWmJ0Q2hjQjkwX2M2YXVRVmZjeEJZZjE1c2V0M2g3MzA0T0w5RmM5MG5fbXNyV3RIMnVYcGxfUEEwc29IMnJMM0xVV3YyS1E0WE5lR0V5eXpqRXBZWTU3VzJMazZreWQ2UU13RV9ndy5TenQ3WGFqbTBnSy11bk05djl5azdB.V50nzzET85j2FAMRGCLqN1sLXZ8WZrfH0G5__WL6UwvrjAZbvj9tjXAnwcIoBeyFU-zvIsjom520-p2JCNoqEg';
$signatureKey = new JWK([
'kty' => 'oct',
'k' => Base64Url::encode('9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8'),
]);
$encryptionKey = new JWK([
'kty' => 'oct',
'k' => '9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8',
]);
$jwsSerializer = new JwsSerializer();
$jws = $jwsSerializer->unserialize($token);
dump($jws);
$jwsVerifier = new JWSVerifier(new AlgorithmManager([
new HS512()
]));
$signatureIsVerified = $jwsVerifier->verifyWithKey($jws, $signatureKey, 0);
if (!$signatureIsVerified) {
exit('Invalid signature');
}
dump('The signature is valid');
$nestedToken = $jws->getPayload();
$jweSerializer = new JweSerializer();
$jwe = $jweSerializer->unserialize($nestedToken);
dump($jwe);
$jweDecrypter = new JWEDecrypter(
new AlgorithmManager([new Dir()]),
new AlgorithmManager([new A128CBCHS256()]),
new CompressionMethodManager([new Deflate()])
);
$decryptionSuccess = $jweDecrypter->decryptUsingKey($jwe, $encryptionKey, 0);
if (!$decryptionSuccess) {
exit('Unable to decrypt the token');
}
dump('The token has been decrypted');
dump($jwe->getPayload());
dump(json_encode($signatureKey), json_encode($encryptionKey));
Apereo CAS 单点登录发布了以下 JWT。
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.ZXlKNmFYQWlPaUpFUlVZaUxDSmhiR2NpT2lKa2FYSWlMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySWl3aWRIbHdJam9pU2xkVUluMC4uREJXMFNUa19OSUVrMmFCVElJNHVnUS5qX3l4a1BVOHNzQ2tCUkdrdjN2RGI0QjFyVDRHWEhzRUJtTlJvTVR0d0hvMjc0NF96cHIzaW1JUk15ek1nU0RIcF9xcXFIQVVnNUNvM3JuM0FTQWUzS1VaMmFsR1B1SmIzT3UxN0hGR2t6a0RDS29CamdHdU9LVHowMlpfVWpYcm1hZXg0RDVyOUt1blNZYWxTWVBDTFU3TncyZEZVWHBwWnlrb3pQdXl6RFFadjZVMDlQaXgxa1gtLW9obUpFVUZJWlN6Vi1DQUs1RTRsSmtWU3ZrZ1gxSmVBMkVjNlY4aFJUSzFIMXRmb2t6Y09nNlJXNElWN05JNVJUQW8ycmlIVlVnLV94czZIY2JFcFZxR0hlVW5QNmF0Nl9zLTFnbGMzTTFzeHBJcmxBN3FEblhPUGt1ZjFmbnpwcEpFVmZWVTV2LWpOUDZQQ0ZnMjA2S2pjeDBYYlRVX0hWN1NyUUhyWUx2Y0gwVWlWVjljZGNOWmJ0Q2hjQjkwX2M2YXVRVmZjeEJZZjE1c2V0M2g3MzA0T0w5RmM5MG5fbXNyV3RIMnVYcGxfUEEwc29IMnJMM0xVV3YyS1E0WE5lR0V5eXpqRXBZWTU3VzJMazZreWQ2UU13RV9ndy5TenQ3WGFqbTBnSy11bk05djl5azdB.V50nzzET85j2FAMRGCLqN1sLXZ8WZrfH0G5__WL6UwvrjAZbvj9tjXAnwcIoBeyFU-zvIsjom520-p2JCNoqEg
我知道它是使用 JWE standard 加密的 JWT。加密密钥如下。
9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8
签名密码如下。
9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8
用于正确解码此 JWT 的 java 代码如下。
public Assertion validate(String ticket) throws TicketValidationException {
try {
System.out.println("ticket="+ticket);
final Key key = new AesKey(signingKey.getBytes(StandardCharsets.UTF_8));
final JsonWebSignature jws = new JsonWebSignature();
jws.setCompactSerialization(ticket);
jws.setKey(key);
if (!jws.verifySignature()) {
throw new TicketValidationException("JWT verification failed");
}
final byte[] decodedBytes = Base64.decodeBase64(jws.getEncodedPayload().getBytes(StandardCharsets.UTF_8));
final String decodedPayload = new String(decodedBytes, StandardCharsets.UTF_8);
final JsonWebEncryption jwe = new JsonWebEncryption();
final JsonWebKey jsonWebKey = JsonWebKey.Factory
.newJwk("\n" + "{\"kty\":\"oct\",\n" + " \"k\":\"" + encryptionKey + "\"\n" + "}");
jwe.setCompactSerialization(decodedPayload);
jwe.setKey(new AesKey(jsonWebKey.getKey().getEncoded()));
System.out.println("JWT ---> "+jwe.getPlaintextString());
JSONParser parser = new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE);
JSONObject json = (JSONObject) parser.parse(jwe.getPlaintextString());
return new AssertionImpl(json.getAsString("sub"));
} catch (JoseException | TicketValidationException ex) {
logger.error(Arrays.toString(ex.getStackTrace()));
} catch (ParseException ex) {
java.util.logging.Logger.getLogger(CustomJWTValidator.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
我正在尝试在 net core 2.2 中解码相同的 JWT。代码如下
var encryptionKey = "9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8";
var jsonWebKey = "\n" + "{\"kty\":\"oct\",\n" + " \"k\":\"" + encryptionKey + "\"\n" + "}";
var jwkc = new JsonWebKey(jsonWebKey);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8")),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
TokenDecryptionKey = jwkc,
};
});
我故意禁用了签名验证和任何其他类型的验证。然而,在 JWT 验证中,我有以下错误。
System.ArgumentException: IDX12723: Unable to decode the payload 'ZXlKNmF...5azdB' as Base64Url encoded string. jwtEncodedString: ''. ---> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: e. Path '', line 0, position 0.
负载似乎没有被正确解码。到目前为止,很多谷歌搜索都没有给我任何结果。
我能够完全加载、验证签名和解密令牌。 问题来自您收到的密钥:当签名密钥不是时,加密密钥已经是 base64url 安全编码。
对应的JWK为(分别为签名和加密):
{"kty":"oct","k":"OU8yMlZkN1FKdTNtQk5oT3k4dndaYVNIMVVQZGllV0FqNGY5c2kycS1PODlPMjJWZDdRSnUzbUJOaE95OHZ3WmFTSDFVUGRpZVdBajRmOXNpMnEtTzg"}
和
{"kty":"oct","k":"9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8"}
编辑:作为记录,我使用了 web-token/jwt-framework(PHP 库)和以下脚本:
<?php
use Base64Url\Base64Url;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;
use Jose\Component\Encryption\Algorithm\KeyEncryption\Dir;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEDecrypter;
use Jose\Component\Encryption\Serializer\CompactSerializer as JweSerializer;
use Jose\Component\Signature\Algorithm\HS512;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\CompactSerializer as JwsSerializer;
require_once 'vendor/autoload.php';
$token = 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.ZXlKNmFYQWlPaUpFUlVZaUxDSmhiR2NpT2lKa2FYSWlMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySWl3aWRIbHdJam9pU2xkVUluMC4uREJXMFNUa19OSUVrMmFCVElJNHVnUS5qX3l4a1BVOHNzQ2tCUkdrdjN2RGI0QjFyVDRHWEhzRUJtTlJvTVR0d0hvMjc0NF96cHIzaW1JUk15ek1nU0RIcF9xcXFIQVVnNUNvM3JuM0FTQWUzS1VaMmFsR1B1SmIzT3UxN0hGR2t6a0RDS29CamdHdU9LVHowMlpfVWpYcm1hZXg0RDVyOUt1blNZYWxTWVBDTFU3TncyZEZVWHBwWnlrb3pQdXl6RFFadjZVMDlQaXgxa1gtLW9obUpFVUZJWlN6Vi1DQUs1RTRsSmtWU3ZrZ1gxSmVBMkVjNlY4aFJUSzFIMXRmb2t6Y09nNlJXNElWN05JNVJUQW8ycmlIVlVnLV94czZIY2JFcFZxR0hlVW5QNmF0Nl9zLTFnbGMzTTFzeHBJcmxBN3FEblhPUGt1ZjFmbnpwcEpFVmZWVTV2LWpOUDZQQ0ZnMjA2S2pjeDBYYlRVX0hWN1NyUUhyWUx2Y0gwVWlWVjljZGNOWmJ0Q2hjQjkwX2M2YXVRVmZjeEJZZjE1c2V0M2g3MzA0T0w5RmM5MG5fbXNyV3RIMnVYcGxfUEEwc29IMnJMM0xVV3YyS1E0WE5lR0V5eXpqRXBZWTU3VzJMazZreWQ2UU13RV9ndy5TenQ3WGFqbTBnSy11bk05djl5azdB.V50nzzET85j2FAMRGCLqN1sLXZ8WZrfH0G5__WL6UwvrjAZbvj9tjXAnwcIoBeyFU-zvIsjom520-p2JCNoqEg';
$signatureKey = new JWK([
'kty' => 'oct',
'k' => Base64Url::encode('9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8'),
]);
$encryptionKey = new JWK([
'kty' => 'oct',
'k' => '9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8',
]);
$jwsSerializer = new JwsSerializer();
$jws = $jwsSerializer->unserialize($token);
dump($jws);
$jwsVerifier = new JWSVerifier(new AlgorithmManager([
new HS512()
]));
$signatureIsVerified = $jwsVerifier->verifyWithKey($jws, $signatureKey, 0);
if (!$signatureIsVerified) {
exit('Invalid signature');
}
dump('The signature is valid');
$nestedToken = $jws->getPayload();
$jweSerializer = new JweSerializer();
$jwe = $jweSerializer->unserialize($nestedToken);
dump($jwe);
$jweDecrypter = new JWEDecrypter(
new AlgorithmManager([new Dir()]),
new AlgorithmManager([new A128CBCHS256()]),
new CompressionMethodManager([new Deflate()])
);
$decryptionSuccess = $jweDecrypter->decryptUsingKey($jwe, $encryptionKey, 0);
if (!$decryptionSuccess) {
exit('Unable to decrypt the token');
}
dump('The token has been decrypted');
dump($jwe->getPayload());
dump(json_encode($signatureKey), json_encode($encryptionKey));