Non-repudiation is the assurance that someone cannot deny the validity of something they did.

Let’s see this in action with a simple digital signature. Imagine Alice wants to send a contract to Bob. She signs it with her private key.

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.exceptions import InvalidSignature

# Alice generates a key pair (normally done once)
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)
public_key = private_key.public_key()

# Alice prepares her contract
contract_data = b"I, Alice, agree to sell my house at 123 Main St to Bob for $500,000."

# Alice signs the contract
signature = private_key.sign(
    contract_data,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# Alice sends the contract and signature to Bob
# Bob receives the contract and signature

# Bob verifies the signature using Alice's public key
try:
    public_key.verify(
        signature,
        contract_data,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("Signature is valid. Alice definitely sent this.")
except InvalidSignature:
    print("Signature is invalid. This message might not be from Alice.")

The core problem non-repudiation solves is the "he said, she said" scenario in digital communications. Without a mechanism to prove who originated a message or action, disputes are unresolvable. Think of a financial transaction: if a customer claims they never authorized a payment, how can the bank prove they did? Non-repudiation provides that proof.

Internally, non-repudiation in digital systems typically relies on asymmetric cryptography. When Alice signs the contract, she’s not encrypting the entire contract. Instead, she’s creating a unique fingerprint (a hash) of the contract and then encrypting that hash with her private key. This encrypted hash is the signature. Anyone can then use Alice’s public key to decrypt the signature, revealing the original hash. They then independently calculate the hash of the received contract. If the two hashes match, it proves two things: the contract hasn’t been tampered with since it was signed, and only the holder of Alice’s private key could have created that signature.

The exact levers you control are the choice of cryptographic algorithms (like RSA or ECDSA), the hashing algorithm (SHA-256, SHA-3), and the padding scheme (PSS, PKCS1v15). These choices impact security strength and performance. More importantly, managing the private keys is paramount. A compromised private key means an attacker can forge signatures, completely undermining non-repudiation for that identity. Secure key storage and lifecycle management are thus critical.

The common understanding is that a digital signature encrypts the message. This is a misconception. A digital signature is the result of encrypting a hash of the message with a private key. If the message itself were encrypted, it would be a digital envelope for confidentiality, not a signature for authentication and non-repudiation.

The next problem you’ll run into is managing the trust of public keys.

Want structured learning?

Take the full Cryptography course →