文章目录
8. Signature Scheme with Appendix
简称RSASSA
Two signature schemes with appendix are specified in this document:
- RSASSA-PSS,适用于新应用,使用EMSA-PSS编码封装方案;
- RSASSA-PKCS1-v1_5,处理旧应用兼容性,使用EMSA-PKCS1-v1_5编码封装方案。
To verify a signature constructed with this type of scheme, it is necessary to have the message itself.
签名和验签,其实就是加密和解密,不同的是两种签名的封装方案(Section 9)。
8.1. RSASSA-PSS
8.1.1. Signature Generation
RSASSA-PSS-SIGN (K, M)
K signer’s RSA private key
M message to be signed, an octet string
Output:
S signature, an octet string of length k, where k is the length in octets of the RSA modulus n
一般明文M是一段hash。
Steps:
- EMSA-PSS encoding
EM = EMSA-PSS-ENCODE (M, modBits - 1);
# Note that the octet length of EM will be one less than k if modBits - 1 is divisible by 8 and equal to k otherwise.
- RSA signature:
m = OS2IP (EM);
s = RSASP1 (K, m);
S = I2OSP (s, k);
- Output the signature S
8.1.2. Signature Verification Operation
RSASSA-PSS-VERIFY ((n, e), M, S)
Input:
(n, e) signer’s RSA public key
M message whose signature is to be verified, an octet string
S signature to be verified, an octet string of length k, where k is the length in octets of the RSA modulus n
Output:
"valid signature" or "invalid signature"
Steps:
-
Length checking: S
-
RSA verification:
s = OS2IP (S);
m = RSAVP1 ((n, e), s);
EM = I2OSP (m, emLen);
- EMSA-PSS verification
Result = EMSA-PSS-VERIFY (M, EM, modBits - 1);
# Note that emLen will be one less than k if modBits - 1 is divisible by 8 and equal to k otherwise.
9. Encoding Methods for Signatures with Appendix
9.1. EMSA-PSS
parameterized by
- the choice of hash function
- mask generation function
- salt length
+-----------+
| M |
+-----------+
|
V
Hash
|
V
+--------+----------+----------+
M’ = |Padding1| mHash | salt |
+--------+----------+----------+
|
+--------+----------+ V
DB = |Padding2| salt | Hash
+--------+----------+ |
| |
V |
xor <--- MGF <---|
| |
| |
V V
+-------------------+----------+--+
EM = | maskedDB | H |bc|
+-------------------+----------+--+
注意:DB的结构实际是 DB = PS || 0x01 || salt
,原图中没有1。
参考源码:PyCryptodome, \Crypto\Signature\pss.py
9.1.1. Encoding Operation
EMSA-PSS-ENCODE (M, emBits)
Options:
Hash hash function (hLen denotes the length in octets of the hash function output)
MGF mask generation function
sLen intended length in octets of the salt
Input:
M message to be encoded, an octet string
emBits maximal bit length of the integer OS2IP (EM) (see Section 4.2), at least 8hLen + 8sLen + 9(no padding)
Output:
EM encoded message, an octet string of length emLen = \ceil(emBits/8)
steps:
# 1. Length checking: M length for hashing
# 2
mHash = Hash(M)
# Step 3
if emLen < mhash.digest_size+sLen+2:
raise ValueError("Digest or salt length are too long"
" for given key size.")
# Step 4
# if sLen = 0, then salt is the empty string
salt = randFunc(sLen)
# Step 5 string of length 8 + hLen + sLen
m_prime = bchr(0)*8 + mhash.digest() + salt
# Step 6
h = mhash.new()
h.update(m_prime)
# Step 7
ps = bchr(0)*(emLen - sLen - mhash.digest_size - 2)
# Step 8
db = ps + bchr(1) + salt
# Step 9
dbMask = mgf(h.digest(), emLen - mhash.digest_size - 1)
# Step 10
maskedDB = strxor(db, dbMask)
# Step 11 最左边的字节的左边8*emLen-emBits个位赋值为0
lmask = 0
for i in iter_range(8*emLen-emBits):
lmask = lmask >> 1 | 0x80
maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:]
# Step 12
em = maskedDB + h.digest() + bchr(0xBC)
9.1.2. Verification Operation
EMSA-PSS-VERIFY (M, EM, emBits)
Input:
M message to be verified, an octet string
EM encoded message, an octet string of length emLen = \ceil(emBits/8)
emBits maximal bit length of the integer OS2IP (EM) (see Section 4.2), at least 8hLen + 8sLen + 9
Output:
"consistent" or "inconsistent"
steps:
# 1. Length checking: M length for hashing
# 2.
mHash = Hash(M)
# Step 3
if emLen < mhash.digest_size+sLen+2:
raise ValueError("Incorrect signature")
# Step 4
if ord(em[-1:]) != 0xBC:
raise ValueError("Incorrect signature")
# Step 5
maskedDB = em[:emLen-mhash.digest_size-1]
h = em[emLen-mhash.digest_size-1:-1]
# Step 6
if lmask & bord(em[0]):
raise ValueError("Incorrect signature")
# Step 7
dbMask = mgf(h, emLen-mhash.digest_size-1)
# Step 8
db = strxor(maskedDB, dbMask)
# Step 9
db = bchr(bord(db[0]) & ~lmask) + db[1:]
# Step 10
if not db.startswith(bchr(0)*(emLen-mhash.digest_size-sLen-2) + bchr(1)):
raise ValueError("Incorrect signature")
# Step 11
if sLen > 0:
salt = db[-sLen:]
else:
salt = b""
# Step 12
m_prime = bchr(0)*8 + mhash.digest() + salt
# Step 13
hobj = mhash.new()
hobj.update(m_prime)
hp = hobj.digest()
# Step 14
if h != hp:
raise ValueError("Incorrect signature")
实现
https://github.com/C0deStarr/CryptoImp/tree/main/pubkey/rsa
- pkcs1_pss.h
- pkcs1_pss.c
参考资料
RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2