2

I wrote a test demo of signature & verification complete process base on rsa, which helps me to figure out the logic of the process.

# https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa

# Preparation phase
# Generate key pairs
# private_key contains the both private key and public key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

# Serilize the keys
from cryptography.hazmat.primitives import serialization

pem = private_key.private_bytes(
   encoding=serialization.Encoding.PEM,
   format=serialization.PrivateFormat.PKCS8,
   encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword')
)
with open('private-key.pem', 'wb') as f:
    f.write(pem)
    f.close()

public_key = private_key.public_key()
pem = public_key.public_bytes(
   encoding=serialization.Encoding.PEM,
   format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with open('public-key.pem', 'wb') as f:
    f.write(pem)
    f.close()

# Signer
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import utils

with open('private-key.pem', 'rb') as f:
    private_key = serialization.load_pem_private_key(
        f.read(),
        password=b'mypassword',
        backend=default_backend()
    )

    chosen_hash = hashes.SHA256()
    hasher = hashes.Hash(chosen_hash, default_backend())
    hasher.update(b"data & ")
    hasher.update(b"more data")
    digest = hasher.finalize()

    signature = private_key.sign(
        digest,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        utils.Prehashed(chosen_hash)
    )

    with open('signature', 'wb') as f:
        f.write(signature)
        f.close()

# Verifier
chosen_hash = hashes.SHA256()
hasher = hashes.Hash(chosen_hash, default_backend())
hasher.update(b"data & ")
hasher.update(b"more data")
digest = hasher.finalize()

hasher1 = hashes.Hash(chosen_hash, default_backend())
hasher1.update(b"data & more data")
digest1 = hasher1.finalize()
print(digest == digest1)

with open('signature', 'rb') as f:
    signature = f.read()

with open('public-key.pem', 'rb') as f:
    public_key  = serialization.load_pem_public_key(
        f.read(),
        backend=default_backend()
    )

    if isinstance(public_key, rsa.RSAPublicKey):
        public_key.verify(
            signature,
            digest,
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            utils.Prehashed(chosen_hash)
        )

Question:

Does the padding type(eg. PSS) having to be known as input when verification?

But in CLI Generate EC KeyPair from OpenSSL command line

openssl dgst -sha256 -verify public.pem -signature msg.signature.txt msg.digest.txt

Why here didn't mention the padding? I think no matter the key pairs algorithm(ECC or RSA) is different or not, the inputs parameter of (standard?) verification method shall be the same.

Another question, I saw in python having isinstance(public_key, rsa.RSAPublicKey) can find out the algorithm of the keys.

Does the algorithm type also necessary for the verification method?

Like inside the lib may having such ecc_verify rsa_verify methods.

BTW for my understanding, the verify method parameter(same as openssl CLI):

  • public key
  • hash type
  • signature
JustWe
  • 4,250
  • 3
  • 39
  • 90

1 Answers1

2

Does the padding type(eg. PSS) having to be known as input when verification?

Yes, the padding is a required configuration parameter that should be known beforehand.

Why here didn't mention the padding?

ECDSA signature verification doesn't require padding; it is significantly different from RSA signature generation / verification.

There is only one used standard for it, as was the case previously for RSA (PKCS#1 v1.5 padding). PSS was only added later in the RSA PKCS#1 standards when version 2.0 was published.

Does the algorithm type also necessary for the verification method?

Although there is probably not a direct attack, you should assume that the verification algorithm is known in advance, just like with the padding method. RSA as described in PKCS#1 has at least two signature generation functions and there are more in other standards - although those are not common at all.

BTW for my understanding, the verify method parameter(same as openssl CLI):

As you've already seen, RSA PSS uses two hash functions, one for hashing the input data and one for the internal MGF1 function used for padding. So there is not one hash type, but two. The hash types are not necessarily the same and implementations differ on how the MGF1 hash is determined (specifying it explicitly, as you do, is for the best).

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Thanks, _you should assume that the verification algorithm is known in advance_, So the algorithm can be known from keys like `isinstance(public_key, rsa.RSAPublicKey)`? – JustWe Oct 04 '19 at 02:18
  • No, the verification algorithm should be established by the protocol. The key can be used for any signature generation algorithm based on RSA. – Maarten Bodewes Oct 04 '19 at 02:36