openssl - 为什么 openssl 生成的签名看起来与 pyjwt 生成的签名不同
问题描述
我正在尝试验证使用 PyJWT 创建的 JWT 签名,但它失败了。如果签名是使用 openssl 命令创建的,它就可以工作。
我有两个脚本。
使用 PyJWT 和 PyOpenSSL 创建 JWT 的 Python 脚本。如果成功,它会在标准输出上吐出 JWT。
执行两个实验的 Bash 脚本。
- 运行 Python 脚本并捕获 JWT。解码标头、有效负载部分。构造要签名的消息。使用 openssl 命令创建签名(使用 dgst),使用公钥进行验证。
- 从 JWT 解码 heder、payload、签名部分。使用 openssl 命令验证使用公钥创建的 JWT 签名。
实验一成功,二失败。
我对类似问题的回答很少,并试图确保
- 我使用 urlsafe b64 编码
- 我使用 openssl dgst 命令从已签名的输入消息中创建散列。
- 移动数据时使用 echo -n
使用 openssl 命令生成的签名验证成功。使用 PyJWT 生成的签名无法通过 openssl 验证。使用 PyJWT 创建的 JWT 使用 PyJWT 成功解码。
我已经没有关于调试这个的想法了。任何帮助,方向都非常感谢。
jwttest.py(需要 PyJwt、PyOpenSSL)
import sys
import base64
import jwt
'''
# Just in case keys are not available
privkey="-----BEGIN PRIVATE KEY-----\n" \
"MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC8JuSavoT2vyZi\n" \
"2RsQ0BFBySQVbK2JJPXXi1O33D3JZhUjQhyRh4yaG6ubirdM/r0eZeADdD047T8i\n" \
"wXFxH/dCZun7AF1dBcXxx1/Jr1VsNiaymXPrnRUBSrCSjqNEJIEbRiKna/JY8i6q\n" \
"cXZRTOYead8fXrTIWJRUTx5F4MNAXqdZ5v/oAsxXc1E7il55vOBDgKZSW4rV7SRC\n" \
"W4zqQA/PE9FmkrygV2x4Kbzc3aObgjgMYR99o6vyOkIhqycBPivwvyLgymDah07r\n" \
"1OR/u2z2w1zX5wD9NyLx2wqbpFQypDr0bOW4CsXuHcPEo206g//6EYlkGOW16ZZr\n" \
"Rhv9t8ipAgMBAAECgf92U/9xUmBMzepWQDPFXxV7SgRndPGuTpBN/lGoT9qLzqd8\n" \
"hRdybsz+HmjOaW7d/Vbyxx8bDP9zzcDnGsE9Y90c5ZxBPvl4hyj15W1YaexPIb80\n" \
"k01T4HZVWaOyiAIl2M9ZV8JziG/hgG3Yw4KlnrcaaXrpP6ZyWULvwtJHIBOrZsei\n" \
"CIlF/cmmwS1uHmXLGTUmZyusOeMfhcQFIh1p3r6dw9Dt6r022FvuMWrqxfsdEAP0\n" \
"kCfhuyyczPIX50gMnVN07ApqH/aMh+77fa8z6pEhqqQeQTkM6ttVzz8l9bEdaHyd\n" \
"T3IXI0G2BfuokGKLAWEKCTFfJbEODDSaSacua9UCgYEA4x+POFom84xJhqgvQdAL\n" \
"ZbDjNadRA6avJ2lDz6PhPSAzq6lleyUj7wv6p1O+37MriPKqkwMXWfZuPXaYEApv\n" \
"VQRxNCofeLjYoueWRAxIts6//1L3ueW1KmQBqGAC5oq3+vy372EvIubmzAmr5hcb\n" \
"3jmzCBjsWzTS/z3s2DpVa78CgYEA1BLjb5zrpnrMP/JJ5SaE9JzGRZ2wmB6wph83\n" \
"U3YYm9j/Qtih24I48EON7zLz/utzGZstoHEwAe8d0F1mxFslsj0A0Y6nIE1rH0Za\n" \
"MAsjkxlU0e+iaZZ9WSVvg7D3i7+dYVKpvHW7SKKYcqvJWNs7u+qkGUqiGuDoEJPr\n" \
"JM5lhZcCgYBlFXa4recIHjfbJp9huyZXbBKznnQAG/94mvEDSPzGJ77Xd90iobUM\n" \
"f1hfgHZDOYr2uIoSRB3wfC00TcP/36UNQZzgip7XK+2/EzNdtdnnAr2Q9Wwr4IBx\n" \
"DXFvbsvbr4GSw0dZ0vcXoYy24tcO4NoWXbfAstb/ANOnpffzhILgIQKBgAw43nSz\n" \
"RX19vEG/M/UJ6EW0t1SRxvitZB7e07BysO5ibiurEoD1G1T1f7uWYyuA5ExIfjOt\n" \
"8kdaQYydpWuRmTWRgHeTUhxxecf+pPn52l4C6rmCpwiQzL6Tgr7DNzENpQNT4UZk\n" \
"PpvsCv8o2VzOnb2xwy1V+Mu1xIoYDEg9wOoXAoGBAN8jWNrtxMQCgCdjwc5gOgs5\n" \
"fRdGVa2yly4dXCzVJl6DN3sEmIOuIZfMXeSNuA40AR6qT36F72WcCVE63ZzKvqtX\n" \
"WPjy/jPyQ9pp1dBKKRQCtktt7Iovuqfkc/XtGg1vv5PCefR4f2GKPCvCL3mPKOEB\n" \
"QWCwIEiwAse5z50XfN10\n" \
"-----END PRIVATE KEY-----\n"
pubkey = "-----BEGIN PUBLIC KEY-----\n" \
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvCbkmr6E9r8mYtkbENAR\n" \
"QckkFWytiST114tTt9w9yWYVI0IckYeMmhurm4q3TP69HmXgA3Q9OO0/IsFxcR/3\n" \
"Qmbp+wBdXQXF8cdfya9VbDYmsplz650VAUqwko6jRCSBG0Yip2vyWPIuqnF2UUzm\n" \
"HmnfH160yFiUVE8eReDDQF6nWeb/6ALMV3NRO4peebzgQ4CmUluK1e0kQluM6kAP\n" \
"zxPRZpK8oFdseCm83N2jm4I4DGEffaOr8jpCIasnAT4r8L8i4Mpg2odO69Tkf7ts\n" \
"9sNc1+cA/Tci8dsKm6RUMqQ69GzluArF7h3DxKNtOoP/+hGJZBjltemWa0Yb/bfI\n" \
"qQIDAQAB\n" \
"-----END PUBLIC KEY-----\n"
'''
data={}
'''
data=
{
"iss": "http://localhost:8080/uaa/oauth/token",
"user_name": "DBA",
"nbf": 1592397960,
"exp": 1621295999
}
'''
def padstr(str):
padding = len(str) % 4
if padding:
data = str
data += '=' * (4 - padding)
return data
return str
if len(sys.argv) < 3 :
print "Usage: " + sys.argv[0] + " <private key file>" + " <public key file>"
exit(1)
with open(sys.argv[1], "r") as f:
privkey=f.read()
#print privkey
with open(sys.argv[2], "r") as f:
pubkey=f.read()
#print pubkey
encoded=jwt.encode(data, privkey, algorithm="RS256")
decoded=jwt.decode(encoded, pubkey, algorithms="RS256")
if( decoded != data ):
print "decoded JWT does not match data"
print "Data=" + str(data)
print "Decoded=" + decoded
exit(1)
else:
print encoded
exit(0)
sign_verification.sh
#!/bin/bash
function create_true_digest {
data_file=$1
digest_file=$2
echo "Creating SHA256 digest for $data_file"
ls -l $data_file
cat $data_file
echo
openssl dgst -sha256 $data_file | cut -d" " -f2 | xxd -r -p > $digest_file
echo "digest stored in $digest_file"
cat ${digest_file} | base64 -w 0 | sed 's/+/-/g' | sed 's/\//_/g' > ${digest_file}.base64
echo "Base64 encoded digest stored in ${digest_file}.base64"
ls -l ${digest_file}
cat ${digest_file}.base64
echo
echo "............................................................"
}
function create_digest {
create_true_digest $1 $2
}
function sign_data {
data_file=$1
pvtkey_file=$2
signature_file=$3
echo "Signing $data_file with $pvtkey_file"
ls -l $data_file
openssl dgst -sha256 -sign $pvtkey_file -out $signature_file $data_file
#openssl dgst -sha256 -sign $pvtkey_file -binary -out $signature_file $data_file
echo "Signature stored in $signature_file"
cat $signature_file | base64 -w 0 | sed 's/+/-/g' | sed 's/\//_/g' > ${signature_file}.base64
echo "Base64 encoded signature stored in ${signature_file}.base64"
ls -l ${signature_file} ${signature_file}.base64
echo "............................................................"
}
function verify_signature {
signature_file=$1
pubkey_file=$2
data_file=$3
echo "Verifying signature $signature_file with $pubkey_file against $data_file"
openssl dgst -sha256 -verify $pubkey_file -signature $signature_file $data_file
echo "............................................................"
}
function experiment_1 {
echo "Experiment 1: This experiment accepts a message to verify"
echo " It uses openssl commands to generate a signature and verifies it"
echo
message_to_verify=$1
#message_to_verify="{\"alg\":\"RS256\",\"typ\":\"JWT\"}.{}"
pvtkey_file=$2
pubkey_file=$3
data_file="sign_data.txt"
rm -f $data_file
echo -n $message_to_verify > $data_file
echo "Data stored in $data_file"
digest_file="data_digest.bin"
rm -f $digest_file
rm -f ${digest_file}.base64
create_digest $data_file $digest_file
signature_file="signature_r.bin"
rm -f $signature_file
rm -f ${signature_file}.base64
sign_data $data_file $pvtkey_file $signature_file
verify_signature $signature_file $pubkey_file $data_file
echo "............................................................"
}
function experiment_2 {
echo "Experiment 2: This experiment accepts a message to verify and signature to verify against"
echo " It uses openssl commands to verify the signature against the message"
message_to_verify=$1
signature=$2 # keep it encoded
pubkey_file=$3
data_file="sign_data.txt"
rm -f $data_file
echo -n $message_to_verify > $data_file
echo "Data stored in $data_file"
cat $data_file
echo
signature_file="signature_r.bin"
rm -f $signature_file
rm -f ${signature_file}.base64
echo -n $signature | sed 's/-/+/g' | sed 's/_/\//g' | base64 -di >$signature_file
echo "Signature stored in $signature_file"
cat $signature_file | base64 -w 0 | sed 's/+/-/g' | sed 's/\//_/g' > ${signature_file}.base64
echo "Base64 encoded signature stored in ${signature_file}.base64"
ls -l ${signature_file} ${signature_file}.base64
verify_signature $signature_file $pubkey_file $data_file
echo "............................................................"
}
if [ $# -lt 2 ]
then
echo "Usage: $0 <private key file> <public key file>"
exit
fi
pvtkey_file=$1
pubkey_file=$2
# Get Base64URL encoded JWT
# Need python 2.7, PyJWT, PyOpenSSL
JWT=`/usr/local/software/python/python2/bin/python jwttest.py $pvtkey_file $pubkey_file`
# Split parts
echo "Ignore base64 warnings..."
header=`echo -n $JWT | cut -d"." -f1 | sed 's/-/+/g' | sed 's/_/\//g' | base64 -di`
payload=`echo -n $JWT | cut -d"." -f2 | sed 's/-/+/g' | sed 's/_/\//g' | base64 -di`
signature=`echo -n $JWT | cut -d"." -f3` # decoding will be done by routines
message_to_verify="${header}.${payload}"
experiment_1 $message_to_verify $pvtkey_file $pubkey_file
experiment_2 $message_to_verify $signature $pubkey_file
解决方案
解决。愚蠢的错误。我假设验证签名的消息是“header.payload”。它是'b64_urlsafe(header).b64_urlsafe(payload)'。我重读了我所指的 JWT 文章,他们确实指出了这一点。很抱歉浪费了您的带宽。
推荐阅读
- python - Pyplot - 可视化列表的直方图
- sapui5 - 如何从外部获取 sap.m.Select 的 selectedKey?
- python - 计算特定员工的工资总和
- c++ - 从返回类型推断类型 T 的模板
- iteration - JQ 拉取不一致的结果
- kentico - 是否有可供购买的 Kentico 小型企业版?
- excel - 仅显示 Excel 数据透视表筛选器的少数成员
- node.js - 如何在环回 4 框架中增加默认的最大请求正文大小?
- sumologic - 在 Sumo Logic 中,如何搜索匹配正则表达式的日志?
- macos - 您如何测量 Metal 中的内存分配和限制?