> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/cis/practical-3-rsa-digital-signature.md).

# Practical 3 — RSA Digital Signature

### Aim

To implement digital signature generation and verification using the RSA algorithm in Python, using the `rsa` library.

### Concept

A **digital signature** is the asymmetric-cryptography equivalent of a handwritten signature: it proves a message genuinely came from the claimed sender (**authentication**) and that it wasn't tampered with in transit (**integrity**), and it stops the sender from later denying they sent it (**non-repudiation**).

RSA (Rivest-Shamir-Adleman) is an asymmetric algorithm that generates a **key pair**:

* A **private key** — kept secret, known only to the sender.
* A **public key** — shared openly with anyone who needs to verify the sender's signatures.

**Important distinction from RSA encryption:** for confidentiality, you encrypt *with the receiver's public key* so only the receiver's private key can decrypt it. For a **digital signature**, the logic is inverted — the sender signs *with their own private key*, and anyone can verify it *with the sender's public key*. This inversion is what proves the signature could only have come from the private-key holder.

#### How it works, step by step

1. The sender computes a **hash** of the message (a fixed-size fingerprint of the data).
2. The sender encrypts (signs) that hash using their **private key** → this produces the **signature**.
3. The sender sends the original message + the signature to the receiver.
4. The receiver independently re-hashes the received message.
5. The receiver uses the sender's **public key** to verify the signature. Internally, this decrypts the signature back to the original hash and compares it to the hash the receiver just computed.
6. If the hashes match → the signature is valid: the message is authentic and unaltered. If they don't match → the message was altered or the signature doesn't belong to the claimed sender.

### Mathematical Formula

RSA relies on modular exponentiation. Key generation:

1. Choose two large prime numbers, `p` and `q`.
2. Compute `n = p × q` (this `n` is the "modulus," part of both keys).
3. Compute Euler's totient: `φ(n) = (p-1)(q-1)`.
4. Choose a public exponent `e`, such that `1 < e < φ(n)` and `gcd(e, φ(n)) = 1`.
5. Compute the private exponent `d`, such that: `d × e ≡ 1 (mod φ(n))`.

This gives:

* **Public key** = `(e, n)`
* **Private key** = `(d, n)`

**Signing** (sender, using private key `d`):

```
signature = H(message)^d mod n
```

where `H(message)` is the hash of the message.

**Verifying** (receiver, using public key `e`):

```
H(message) = signature^e mod n
```

The receiver checks whether this recovered hash matches the hash of the message they received.

The `rsa` Python library handles all of this modular-exponentiation math internally — the code in this practical just calls its high-level functions.

### Python Code

```python
import rsa

# generate keys for the sender
public_key, private_key = rsa.newkeys(512)
message = b'approve project X'

# sender signs the message with their private key
signature = rsa.sign(message, private_key, 'SHA-1')
print("signature generated successfully")

# receiver verifies the message with the sender's public key
try:
    # verify returns the hash algorithm name if successful
    verification = rsa.verify(message, signature, public_key)
    print("signature verified! Hash algorithm used:", verification)
except rsa.VerificationError:
    print("verification failed! signature id forged or message altered")
```

### Line-by-Line Explanation

```python
import rsa
```

Imports the third-party `rsa` library, which provides ready-made functions for RSA key generation, signing, and verification, so we don't have to implement the modular-exponentiation math by hand.

```python
public_key, private_key = rsa.newkeys(512)
```

Calls `rsa.newkeys(512)`, which generates a brand-new RSA **key pair** with a modulus size of **512 bits**. It returns two objects — the public key and the private key — which are unpacked into the two variables `public_key` and `private_key`. (Note: 512 bits is small and used here only for a quick demo/learning exercise; real-world RSA keys should be at least 2048 bits for actual security.)

```python
message = b'approve project X'
```

Defines the message to be signed. The `b'...'` prefix makes this a **bytes** object rather than a regular string — the `rsa` library's signing functions require byte-strings as input, not plain text (`str`).

```python
signature = rsa.sign(message, private_key, 'SHA-1')
```

This is the core signing step:

* `rsa.sign(...)` takes the `message`, the `private_key`, and the name of a hash algorithm (`'SHA-1'` here).
* Internally it hashes the message using SHA-1, then encrypts that hash with the private key using the RSA math described above.
* The result — the digital signature — is stored in the `signature` variable.

```python
print("signature generated successfully")
```

Simply prints a confirmation message once signing has completed, so the user knows this step succeeded.

```python
try:
```

Begins a `try` block. Verification can fail (e.g. if the message was altered or the wrong public key is used), so it's wrapped in exception handling to catch that failure gracefully instead of crashing the program.

```python
    verification = rsa.verify(message, signature, public_key)
```

Calls `rsa.verify(...)`, passing in the (received) `message`, the `signature` to check, and the sender's `public_key`.

* Internally, this decrypts the `signature` using the public key to recover the original hash, independently hashes the given `message`, and compares the two.
* If they match, the function **returns the name of the hash algorithm** that was used (e.g. `'SHA-1'`) — it doesn't return `True`/`False`; a successful return value itself is the proof of validity.
* If they don't match, it doesn't return normally — instead it raises an exception.

```python
    print("signature verified! Hash algorithm used:", verification)
```

If the line above succeeded (no exception raised), this prints a success message along with the hash algorithm name that was returned by `rsa.verify()`.

```python
except rsa.VerificationError:
```

Catches the specific exception `rsa.VerificationError`, which the `rsa` library raises when verification fails — i.e. when the signature doesn't correspond to the given message and public key (meaning the message was altered, the signature is forged, or the wrong key was used).

```python
    print("verification failed! signature id forged or message altered")
```

If verification failed and the exception was caught, this prints a failure message telling the user that the signature could not be trusted. *(Note: this appears to contain a small typo in the original code — "signature id forged" likely intends "signature is forged.")*

### Sample Output

```
signature generated successfully
signature verified! Hash algorithm used: SHA-1
```

### Conclusion

This practical demonstrates how RSA can be used not just for encrypting data, but for **digitally signing** it — allowing a receiver to confirm both the authenticity of the sender and the integrity of the message, using the sender's private key to sign and their public key to verify.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/cis/practical-3-rsa-digital-signature.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
