Path: blob/main/latex-templates/templates/cryptography/rsa_encryption.tex
51 views
unlisted
% RSA Encryption Analysis Template1% Topics: Public-key cryptography, modular arithmetic, key generation, encryption/decryption2% Style: Cryptographic implementation with security analysis34\documentclass[a4paper, 11pt]{article}5\usepackage[utf8]{inputenc}6\usepackage[T1]{fontenc}7\usepackage{amsmath, amssymb}8\usepackage{graphicx}9\usepackage{siunitx}10\usepackage{booktabs}11\usepackage{subcaption}12\usepackage[makestderr]{pythontex}1314% Theorem environments15\newtheorem{definition}{Definition}[section]16\newtheorem{theorem}{Theorem}[section]17\newtheorem{example}{Example}[section]18\newtheorem{remark}{Remark}[section]1920\usepackage[colorlinks=false,hidelinks]{hyperref}2122\title{RSA Encryption: Implementation and Security Analysis}23\author{Cryptography Research Laboratory}24\date{\today}2526\begin{document}27\maketitle2829\begin{abstract}30This report presents a comprehensive computational analysis of the RSA (Rivest-Shamir-Adleman)31public-key cryptosystem, examining the mathematical foundations of modular exponentiation,32key generation procedures, encryption and decryption operations, and security considerations.33We implement RSA encryption with various key sizes (512-bit to 2048-bit), analyze the34computational complexity of modular exponentiation algorithms, demonstrate the relationship35between prime factorization difficulty and key security, and evaluate timing characteristics36that could lead to side-channel vulnerabilities. The analysis includes visualization of the37key generation process, cipher space distribution, and performance metrics across different38implementation parameters.39\end{abstract}4041\section{Introduction}4243Public-key cryptography revolutionized secure communication by solving the key distribution44problem that plagued symmetric encryption systems. The RSA algorithm, published by Rivest,45Shamir, and Adleman in 1978, remains one of the most widely deployed asymmetric encryption46schemes in modern cryptographic protocols. Unlike symmetric systems that require both parties47to share a secret key through a secure channel, RSA enables secure communication over48insecure channels by using a mathematically related key pair: a public key for encryption49and a private key for decryption.5051The security of RSA rests on the computational intractability of factoring large composite52numbers into their prime factors. While multiplying two large primes is computationally53trivial, reversing this operation—given only the product—becomes exponentially difficult as54the prime factors grow larger. This asymmetry between the ease of encryption and the55difficulty of decryption without the private key forms the foundation of RSA's security model.5657\begin{definition}[RSA Key Pair]58An RSA key pair consists of:59\begin{itemize}60\item \textbf{Public key}: $(n, e)$ where $n = pq$ is the modulus (product of two large primes)61and $e$ is the public exponent62\item \textbf{Private key}: $(n, d)$ where $d$ is the private exponent satisfying63$ed \equiv 1 \pmod{\phi(n)}$64\end{itemize}65\end{definition}6667In this analysis, we implement the complete RSA cryptosystem, examine the mathematical68operations underlying key generation and cipher operations, and investigate security69properties through computational experiments with various key sizes and implementation70parameters.7172\section{Mathematical Framework}7374\subsection{Euler's Totient Function and Modular Arithmetic}7576The theoretical foundation of RSA relies on Euler's theorem and properties of modular77arithmetic in finite fields. Understanding these mathematical structures is essential for78comprehending why RSA encryption and decryption operations are inverse functions.7980\begin{definition}[Euler's Totient Function]81For a positive integer $n$, Euler's totient function $\phi(n)$ counts the number of integers82in the range $1$ to $n$ that are coprime to $n$. For two distinct primes $p$ and $q$:83\begin{equation}84\phi(pq) = (p-1)(q-1)85\end{equation}86\end{definition}8788\begin{theorem}[Euler's Theorem]89If $\gcd(a, n) = 1$, then:90\begin{equation}91a^{\phi(n)} \equiv 1 \pmod{n}92\end{equation}93\end{theorem}9495This theorem guarantees that for any message $m$ coprime to $n$, the encryption and96decryption operations form an inverse pair when $ed \equiv 1 \pmod{\phi(n)}$.9798\subsection{RSA Encryption and Decryption}99100\begin{definition}[RSA Cipher Operations]101Given a message $m$ where $0 < m < n$ and $\gcd(m, n) = 1$:102\begin{itemize}103\item \textbf{Encryption}: $c = m^e \bmod n$104\item \textbf{Decryption}: $m = c^d \bmod n$105\end{itemize}106\end{definition}107108\begin{theorem}[RSA Correctness]109For RSA keys $(n, e, d)$ where $ed \equiv 1 \pmod{\phi(n)}$, decryption recovers the110original message:111\begin{equation}112(m^e)^d \equiv m^{ed} \equiv m^{1 + k\phi(n)} \equiv m \cdot (m^{\phi(n)})^k \equiv m \pmod{n}113\end{equation}114\end{theorem}115116The proof follows from Euler's theorem, where $m^{\phi(n)} \equiv 1 \pmod{n}$ for messages117coprime to $n$.118119\section{Key Generation Implementation}120121The security of an RSA system depends critically on proper key generation. Prime selection,122parameter validation, and key size all impact both security and performance. This section123implements the complete key generation algorithm and analyzes the properties of generated124keys.125126We begin by implementing helper functions for primality testing and modular arithmetic, then127construct the full key generation procedure. The implementation uses probabilistic primality128testing (Miller-Rabin) for efficiency, though production systems should use cryptographically129secure random number generation and more rigorous testing.130131\begin{pycode}132import numpy as np133import matplotlib.pyplot as plt134from math import gcd135import random136import time137138np.random.seed(42)139random.seed(42)140141def miller_rabin(n, k=5):142"""Probabilistic primality test using Miller-Rabin algorithm."""143if n < 2:144return False145if n == 2 or n == 3:146return True147if n % 2 == 0:148return False149150# Write n-1 as 2^r * d151r, d = 0, n - 1152while d % 2 == 0:153r += 1154d //= 2155156# Witness loop157for _ in range(k):158a = random.randrange(2, n - 1)159x = pow(a, d, n)160if x == 1 or x == n - 1:161continue162for _ in range(r - 1):163x = pow(x, 2, n)164if x == n - 1:165break166else:167return False168return True169170def generate_prime(bits):171"""Generate a prime number with specified bit length."""172while True:173p = random.getrandbits(bits)174p |= (1 << bits - 1) | 1 # Set MSB and LSB175if miller_rabin(p):176return p177178def extended_gcd(a, b):179"""Extended Euclidean algorithm."""180if a == 0:181return b, 0, 1182gcd_val, x1, y1 = extended_gcd(b % a, a)183x = y1 - (b // a) * x1184y = x1185return gcd_val, x, y186187def mod_inverse(e, phi):188"""Compute modular multiplicative inverse."""189gcd_val, x, _ = extended_gcd(e, phi)190if gcd_val != 1:191return None192return (x % phi + phi) % phi193194def generate_rsa_keypair(bits):195"""Generate RSA key pair with specified bit length."""196# Generate two distinct primes197p = generate_prime(bits // 2)198q = generate_prime(bits // 2)199while p == q:200q = generate_prime(bits // 2)201202# Compute modulus and totient203n = p * q204phi_n = (p - 1) * (q - 1)205206# Choose public exponent (commonly 65537)207e = 65537208if gcd(e, phi_n) != 1:209e = 3210while gcd(e, phi_n) != 1:211e += 2212213# Compute private exponent214d = mod_inverse(e, phi_n)215216return (n, e, d, p, q, phi_n)217218def encrypt_rsa(message, e, n):219"""RSA encryption: c = m^e mod n."""220return pow(message, e, n)221222def decrypt_rsa(ciphertext, d, n):223"""RSA decryption: m = c^d mod n."""224return pow(ciphertext, d, n)225226# Generate example RSA keys with different sizes227key_sizes = [512, 1024, 2048]228keys = {}229generation_times = []230231for key_size in key_sizes:232start_time = time.time()233n, e, d, p, q, phi_n = generate_rsa_keypair(key_size)234gen_time = time.time() - start_time235236keys[key_size] = {237'n': n, 'e': e, 'd': d, 'p': p, 'q': q,238'phi_n': phi_n, 'gen_time': gen_time239}240generation_times.append(gen_time)241242# Detailed analysis of 1024-bit key243n_1024 = keys[1024]['n']244e_1024 = keys[1024]['e']245d_1024 = keys[1024]['d']246p_1024 = keys[1024]['p']247q_1024 = keys[1024]['q']248phi_1024 = keys[1024]['phi_n']249250# Create visualization of key generation process251fig = plt.figure(figsize=(14, 10))252253# Plot 1: Prime number bit distribution254ax1 = fig.add_subplot(3, 3, 1)255bit_positions_p = [int(b) for b in bin(p_1024)[2:]]256bit_positions_q = [int(b) for b in bin(q_1024)[2:]]257x_p = np.arange(len(bit_positions_p))258x_q = np.arange(len(bit_positions_q))259ax1.step(x_p, bit_positions_p, where='mid', linewidth=1.5, label='Prime p', color='steelblue')260ax1.step(x_q, bit_positions_q, where='mid', linewidth=1.5, label='Prime q', color='coral', alpha=0.7)261ax1.set_xlabel('Bit Position')262ax1.set_ylabel('Bit Value')263ax1.set_title('Prime Factor Bit Patterns (1024-bit RSA)')264ax1.legend(fontsize=8)265ax1.set_ylim(-0.1, 1.1)266ax1.grid(True, alpha=0.3)267\end{pycode}268269The key generation algorithm demonstrates several important properties: the primes $p$ and270$q$ must be randomly selected from the appropriate range, the public exponent $e$ is commonly271chosen as 65537 for efficiency (small Hamming weight enables fast encryption), and the272private exponent $d$ is computed as the modular multiplicative inverse of $e$ modulo273$\phi(n)$. For our 1024-bit example, we generated primes $p = \py{p_1024}$ and274$q = \py{q_1024}$, yielding modulus $n = \py{n_1024}$ and private exponent $d = \py{d_1024}$.275276\begin{pycode}277# Plot 2: Key generation time vs. key size278ax2 = fig.add_subplot(3, 3, 2)279ax2.bar(range(len(key_sizes)), generation_times, color='steelblue', edgecolor='black', width=0.6)280ax2.set_xticks(range(len(key_sizes)))281ax2.set_xticklabels([f'{k}-bit' for k in key_sizes])282ax2.set_xlabel('Key Size')283ax2.set_ylabel('Generation Time (seconds)')284ax2.set_title('Key Generation Performance')285ax2.grid(True, alpha=0.3, axis='y')286for i, t in enumerate(generation_times):287ax2.text(i, t, f'{t:.3f}s', ha='center', va='bottom', fontsize=9)288289# Plot 3: Modulus size comparison290ax3 = fig.add_subplot(3, 3, 3)291modulus_bits = [keys[k]['n'].bit_length() for k in key_sizes]292ax3.plot(key_sizes, modulus_bits, 'o-', linewidth=2, markersize=8,293color='steelblue', markeredgecolor='black')294ax3.plot(key_sizes, key_sizes, '--', linewidth=1.5, color='coral',295label='Target size', alpha=0.7)296ax3.set_xlabel('Target Key Size (bits)')297ax3.set_ylabel('Actual Modulus Size (bits)')298ax3.set_title('Key Size Validation')299ax3.legend(fontsize=8)300ax3.grid(True, alpha=0.3)301\end{pycode}302303\begin{figure}[htbp]304\centering305\includegraphics[width=0.32\textwidth]{rsa_keygen_plot1.pdf}306\includegraphics[width=0.32\textwidth]{rsa_keygen_plot2.pdf}307\includegraphics[width=0.32\textwidth]{rsa_keygen_plot3.pdf}308\caption{RSA key generation analysis showing (left) the binary representation of prime factors309for a 1024-bit key pair, demonstrating the random bit distribution essential for security;310(center) computational cost of key generation increasing with key size due to primality testing311complexity; (right) verification that generated moduli match target bit lengths. The 512-bit312key generates in \py{f"{generation_times[0]:.3f}"} seconds, while 2048-bit keys require313\py{f"{generation_times[2]:.3f}"} seconds, reflecting the $O(k^3)$ complexity of primality314testing where $k$ is the bit length.}315\label{fig:keygen}316\end{figure}317318The key generation times demonstrate the computational cost of finding large primes through319probabilistic testing. While 512-bit keys generate rapidly, production-grade 2048-bit keys320require significantly more computation due to the cubic complexity of modular exponentiation321in the Miller-Rabin test.322323\section{Encryption and Decryption Operations}324325With keys generated, we now examine the core cipher operations. Both encryption and326decryption rely on modular exponentiation, an operation that must be implemented efficiently327to avoid exponential-time computation. Modern implementations use the square-and-multiply328algorithm to reduce complexity from $O(e)$ to $O(\log e)$ multiplications.329330\begin{pycode}331# Test encryption/decryption with various messages332messages = [42, 1337, 31415, 271828, 314159, 999999]333ciphertexts_1024 = []334decrypted_1024 = []335encryption_times = []336decryption_times = []337338for m in messages:339# Encryption340start = time.time()341c = encrypt_rsa(m, e_1024, n_1024)342enc_time = time.time() - start343encryption_times.append(enc_time)344ciphertexts_1024.append(c)345346# Decryption347start = time.time()348m_dec = decrypt_rsa(c, d_1024, n_1024)349dec_time = time.time() - start350decryption_times.append(dec_time)351decrypted_1024.append(m_dec)352353# Verify correctness354all_correct = all(m == m_dec for m, m_dec in zip(messages, decrypted_1024))355356# Plot 4: Encryption/Decryption timing357ax4 = fig.add_subplot(3, 3, 4)358x_pos = np.arange(len(messages))359width = 0.35360ax4.bar(x_pos - width/2, encryption_times, width, label='Encryption',361color='steelblue', edgecolor='black')362ax4.bar(x_pos + width/2, decryption_times, width, label='Decryption',363color='coral', edgecolor='black')364ax4.set_xlabel('Message Index')365ax4.set_ylabel('Time (seconds)')366ax4.set_title('Cipher Operation Performance (1024-bit)')367ax4.set_xticks(x_pos)368ax4.set_xticklabels([f'M{i+1}' for i in range(len(messages))])369ax4.legend(fontsize=8)370ax4.grid(True, alpha=0.3, axis='y')371372# Plot 5: Ciphertext distribution373ax5 = fig.add_subplot(3, 3, 5)374normalized_ciphers = [c / n_1024 for c in ciphertexts_1024]375ax5.scatter(range(len(normalized_ciphers)), normalized_ciphers, s=100,376c='steelblue', edgecolor='black', alpha=0.7)377ax5.axhline(y=0.5, color='red', linestyle='--', linewidth=1.5,378alpha=0.5, label='Median of range')379ax5.set_xlabel('Message Index')380ax5.set_ylabel('Normalized Ciphertext (c/n)')381ax5.set_title('Ciphertext Distribution in Key Space')382ax5.set_ylim(0, 1)383ax5.legend(fontsize=8)384ax5.grid(True, alpha=0.3)385\end{pycode}386387The timing analysis reveals an important asymmetry: encryption with the small public exponent388$e = 65537$ executes in \py{f"{np.mean(encryption_times)*1000:.4f}"} milliseconds on average,389while decryption with the large private exponent $d$ requires390\py{f"{np.mean(decryption_times)*1000:.4f}"} milliseconds. This performance difference is391intentional—public key operations (encryption and signature verification) should be fast,392while private key operations need not be optimized for speed since they occur less frequently.393394\begin{pycode}395# Plot 6: Message expansion visualization396ax6 = fig.add_subplot(3, 3, 6)397message_bits = [m.bit_length() for m in messages]398cipher_bits = [c.bit_length() for c in ciphertexts_1024]399x_msg = np.arange(len(messages))400ax6.bar(x_msg - 0.2, message_bits, 0.4, label='Plaintext',401color='lightblue', edgecolor='black')402ax6.bar(x_msg + 0.2, cipher_bits, 0.4, label='Ciphertext',403color='steelblue', edgecolor='black')404ax6.axhline(y=1024, color='red', linestyle='--', linewidth=1.5,405alpha=0.5, label='Modulus size')406ax6.set_xlabel('Message Index')407ax6.set_ylabel('Bit Length')408ax6.set_title('Message Expansion (Plaintext → Ciphertext)')409ax6.set_xticks(x_msg)410ax6.set_xticklabels([f'M{i+1}' for i in range(len(messages))])411ax6.legend(fontsize=7)412ax6.grid(True, alpha=0.3, axis='y')413414plt.tight_layout()415plt.savefig('rsa_keygen_plot1.pdf', dpi=150, bbox_inches='tight')416plt.savefig('rsa_keygen_plot2.pdf', dpi=150, bbox_inches='tight')417plt.savefig('rsa_keygen_plot3.pdf', dpi=150, bbox_inches='tight')418plt.close()419420# Continue with new figure421fig2 = plt.figure(figsize=(14, 10))422ax4_new = fig2.add_subplot(3, 3, 1)423x_pos = np.arange(len(messages))424width = 0.35425ax4_new.bar(x_pos - width/2, encryption_times, width, label='Encryption',426color='steelblue', edgecolor='black')427ax4_new.bar(x_pos + width/2, decryption_times, width, label='Decryption',428color='coral', edgecolor='black')429ax4_new.set_xlabel('Message Index')430ax4_new.set_ylabel('Time (seconds)')431ax4_new.set_title('Cipher Operation Performance (1024-bit)')432ax4_new.set_xticks(x_pos)433ax4_new.set_xticklabels([f'M{i+1}' for i in range(len(messages))])434ax4_new.legend(fontsize=8)435ax4_new.grid(True, alpha=0.3, axis='y')436437ax5_new = fig2.add_subplot(3, 3, 2)438normalized_ciphers = [c / n_1024 for c in ciphertexts_1024]439ax5_new.scatter(range(len(normalized_ciphers)), normalized_ciphers, s=100,440c='steelblue', edgecolor='black', alpha=0.7)441ax5_new.axhline(y=0.5, color='red', linestyle='--', linewidth=1.5,442alpha=0.5, label='Median of range')443ax5_new.set_xlabel('Message Index')444ax5_new.set_ylabel('Normalized Ciphertext (c/n)')445ax5_new.set_title('Ciphertext Distribution in Key Space')446ax5_new.set_ylim(0, 1)447ax5_new.legend(fontsize=8)448ax5_new.grid(True, alpha=0.3)449450ax6_new = fig2.add_subplot(3, 3, 3)451message_bits = [m.bit_length() for m in messages]452cipher_bits = [c.bit_length() for c in ciphertexts_1024]453x_msg = np.arange(len(messages))454ax6_new.bar(x_msg - 0.2, message_bits, 0.4, label='Plaintext',455color='lightblue', edgecolor='black')456ax6_new.bar(x_msg + 0.2, cipher_bits, 0.4, label='Ciphertext',457color='steelblue', edgecolor='black')458ax6_new.axhline(y=1024, color='red', linestyle='--', linewidth=1.5,459alpha=0.5, label='Modulus size')460ax6_new.set_xlabel('Message Index')461ax6_new.set_ylabel('Bit Length')462ax6_new.set_title('Message Expansion (Plaintext → Ciphertext)')463ax6_new.set_xticks(x_msg)464ax6_new.set_xticklabels([f'M{i+1}' for i in range(len(messages))])465ax6_new.legend(fontsize=7)466ax6_new.grid(True, alpha=0.3, axis='y')467\end{pycode}468469\begin{figure}[htbp]470\centering471\includegraphics[width=\textwidth]{rsa_cipher_operations.pdf}472\caption{RSA encryption and decryption analysis for 1024-bit keys: (left) timing comparison473showing decryption is significantly slower than encryption due to the large private exponent,474with average encryption time of \py{f"{np.mean(encryption_times)*1000:.3f}"} ms versus475decryption time of \py{f"{np.mean(decryption_times)*1000:.3f}"} ms; (center) normalized476ciphertext distribution demonstrating that encrypted values span the full modulus space477uniformly, preventing statistical attacks; (right) message expansion showing all ciphertexts478approach the full modulus bit length regardless of plaintext size, illustrating why RSA is479not suitable for bulk encryption without hybrid schemes.}480\label{fig:cipher}481\end{figure}482483The ciphertext distribution analysis confirms that encrypted messages occupy the full range484of the modulus $n$, with normalized values spanning $[0, 1]$ uniformly. This property is485essential for security—predictable patterns in ciphertext distribution could leak information486about plaintext structure.487488\section{Security Analysis}489490\subsection{Factorization Complexity}491492The security of RSA fundamentally depends on the difficulty of factoring the modulus $n$ into493its prime components $p$ and $q$. While legitimate users possess these factors (enabling494efficient computation of $\phi(n)$ and thus $d$), adversaries must resort to factorization495algorithms whose runtime grows exponentially with key size.496497\begin{pycode}498# Demonstrate factorization difficulty with smaller composite numbers499def trial_division_time(n):500"""Measure time for trial division factorization."""501start = time.time()502for i in range(2, int(n**0.5) + 1):503if n % i == 0:504elapsed = time.time() - start505return i, n // i, elapsed506return None, None, time.time() - start507508# Test with composite numbers of increasing size509composite_bits = [16, 20, 24, 28, 32]510composites = []511factorization_times = []512513for bits in composite_bits:514p_small = generate_prime(bits // 2)515q_small = generate_prime(bits // 2)516n_small = p_small * q_small517composites.append(n_small)518519p_found, q_found, fact_time = trial_division_time(n_small)520factorization_times.append(fact_time)521522# Plot 7: Factorization time growth523ax7 = fig2.add_subplot(3, 3, 4)524ax7.semilogy(composite_bits, factorization_times, 'o-', linewidth=2,525markersize=8, color='coral', markeredgecolor='black')526ax7.set_xlabel('Composite Bit Size')527ax7.set_ylabel('Factorization Time (seconds, log scale)')528ax7.set_title('Trial Division Attack Complexity')529ax7.grid(True, alpha=0.3, which='both')530for i, (bits, t) in enumerate(zip(composite_bits, factorization_times)):531if t > 0.0001:532ax7.annotate(f'{t:.4f}s', xy=(bits, t), xytext=(5, 5),533textcoords='offset points', fontsize=7)534\end{pycode}535536Even with the naive trial division algorithm, factorization time grows exponentially. For our537test composites, the 16-bit number factored in \py{f"{factorization_times[0]:.6f}"} seconds,538while the 32-bit number required \py{f"{factorization_times[-1]:.4f}"} seconds. Extrapolating539to 1024-bit or 2048-bit moduli reveals the computational infeasibility of factorization attacks—540modern factorization algorithms like the General Number Field Sieve would require centuries of541computing time for properly sized RSA keys.542543\begin{pycode}544# Plot 8: Key size security margin545ax8 = fig2.add_subplot(3, 3, 5)546recommended_bits = [1024, 2048, 3072, 4096]547security_bits = [80, 112, 128, 152] # Approximate symmetric equivalents548years_secure = [2010, 2030, 2040, 2050] # Rough estimates549550ax8_twin = ax8.twinx()551ax8.bar(np.arange(len(recommended_bits)) - 0.2, security_bits, 0.4,552label='Security bits', color='steelblue', edgecolor='black')553ax8_twin.plot(np.arange(len(recommended_bits)), years_secure, 'o-',554linewidth=2, markersize=8, color='coral',555markeredgecolor='black', label='Safe until')556ax8.set_xlabel('RSA Key Size (bits)')557ax8.set_ylabel('Equivalent Symmetric Security (bits)', color='steelblue')558ax8_twin.set_ylabel('Estimated Safe Until (year)', color='coral')559ax8.set_xticks(np.arange(len(recommended_bits)))560ax8.set_xticklabels(recommended_bits)561ax8.set_title('Key Size Security Recommendations')562ax8.tick_params(axis='y', labelcolor='steelblue')563ax8_twin.tick_params(axis='y', labelcolor='coral')564ax8.grid(True, alpha=0.3, axis='x')565566# Plot 9: Modular exponentiation operation count567ax9 = fig2.add_subplot(3, 3, 6)568exponent_bits = [e_1024.bit_length(), d_1024.bit_length()]569operations = [exponent_bits[0] * 1.5, exponent_bits[1] * 1.5] # Average for square-and-multiply570labels = ['Public key\n(encryption)', 'Private key\n(decryption)']571colors = ['steelblue', 'coral']572ax9.bar(range(2), operations, color=colors, edgecolor='black', width=0.6)573ax9.set_xticks(range(2))574ax9.set_xticklabels(labels, fontsize=9)575ax9.set_ylabel('Approximate Modular Multiplications')576ax9.set_title('Computational Cost by Operation Type')577for i, (ops, bits) in enumerate(zip(operations, exponent_bits)):578ax9.text(i, ops, f'{int(ops)}\n({bits}-bit exp)',579ha='center', va='bottom', fontsize=8)580ax9.grid(True, alpha=0.3, axis='y')581\end{pycode}582583\begin{figure}[htbp]584\centering585\includegraphics[width=\textwidth]{rsa_security_analysis.pdf}586\caption{RSA security analysis demonstrating (left) exponential growth of factorization time587with composite number size, showing why 1024-bit and larger moduli are computationally secure;588(center) security margin recommendations indicating that 2048-bit keys provide 112-bit equivalent589security and should remain secure until 2030 against classical computers; (right) operation count590comparison showing public key operations require approximately \py{int(operations[0])} modular591multiplications versus \py{int(operations[1])} for private key operations, explaining the592performance asymmetry observed in timing tests.}593\label{fig:security}594\end{figure}595596Current cryptographic standards recommend minimum 2048-bit keys for new deployments, with5973072-bit or 4096-bit keys for long-term security. The 1024-bit keys demonstrated in this598analysis should only be used for educational purposes, as modern computational resources have599rendered them potentially vulnerable to well-funded adversaries.600601\subsection{Timing Attacks and Side-Channel Resistance}602603Beyond mathematical security, practical RSA implementations must guard against side-channel604attacks that exploit physical properties of computation rather than mathematical weaknesses.605Timing attacks, in particular, can leak information about the private exponent through606variations in decryption time based on the number of operations performed.607608\begin{pycode}609# Simulate timing attack vulnerability610def decrypt_timing_vulnerable(c, d, n):611"""Decryption with timing variation based on exponent bits."""612result = 1613base = c614exp = d615op_count = 0616617while exp > 0:618if exp & 1:619result = (result * base) % n620op_count += 1621base = (base * base) % n622op_count += 1623exp >>= 1624625return result, op_count626627# Test messages with different characteristics628test_ciphers = ciphertexts_1024[:4]629operation_counts = []630631for c in test_ciphers:632_, ops = decrypt_timing_vulnerable(c, d_1024, n_1024)633operation_counts.append(ops)634635# Plot timing correlation636ax10 = fig2.add_subplot(3, 3, 7)637ax10.bar(range(len(operation_counts)), operation_counts,638color='coral', edgecolor='black', width=0.6, alpha=0.7)639avg_ops = np.mean(operation_counts)640ax10.axhline(y=avg_ops, color='steelblue', linestyle='--',641linewidth=2, label=f'Average: {avg_ops:.0f} ops')642ax10.set_xlabel('Ciphertext Index')643ax10.set_ylabel('Operation Count')644ax10.set_title('Timing Side-Channel Vulnerability')645ax10.set_xticks(range(len(operation_counts)))646ax10.legend(fontsize=8)647ax10.grid(True, alpha=0.3, axis='y')648for i, ops in enumerate(operation_counts):649ax10.text(i, ops, f'{ops}', ha='center', va='bottom', fontsize=8)650\end{pycode}651652The operation count variation demonstrates why constant-time implementations are crucial for653RSA security. While our naive implementation shows operation counts ranging from654\py{min(operation_counts)} to \py{max(operation_counts)}, production libraries use techniques655like Montgomery multiplication and blinding to ensure timing independence from private key bits.656657\begin{pycode}658# Plot 11: Padding scheme importance659ax11 = fig2.add_subplot(3, 3, 8)660# Demonstrate textbook RSA malleability661m1, m2 = 100, 200662c1 = encrypt_rsa(m1, e_1024, n_1024)663c2 = encrypt_rsa(m2, e_1024, n_1024)664c_product = (c1 * c2) % n_1024665m_product = decrypt_rsa(c_product, d_1024, n_1024)666expected_product = (m1 * m2) % n_1024667668# Visualize malleability property669operations = ['$m_1$', '$m_2$', '$m_1 \\times m_2$']670plaintexts = [m1, m2, m_product]671ax11.bar(range(len(operations)), plaintexts, color='lightcoral',672edgecolor='black', width=0.6, alpha=0.7)673ax11.set_xticks(range(len(operations)))674ax11.set_xticklabels(operations, fontsize=10)675ax11.set_ylabel('Plaintext Value')676ax11.set_title('Textbook RSA Malleability Attack')677ax11.grid(True, alpha=0.3, axis='y')678for i, p in enumerate(plaintexts):679ax11.text(i, p, f'{p}', ha='center', va='bottom', fontsize=8)680681# Plot 12: Performance scaling682ax12 = fig2.add_subplot(3, 3, 9)683ax12.plot(key_sizes, generation_times, 'o-', linewidth=2, markersize=8,684color='steelblue', markeredgecolor='black', label='Key generation')685ax12.set_xlabel('Key Size (bits)')686ax12.set_ylabel('Time (seconds, log scale)')687ax12.set_yscale('log')688ax12.set_title('Performance Scaling with Key Size')689ax12.legend(fontsize=8)690ax12.grid(True, alpha=0.3, which='both')691692plt.tight_layout()693plt.savefig('rsa_cipher_operations.pdf', dpi=150, bbox_inches='tight')694plt.savefig('rsa_security_analysis.pdf', dpi=150, bbox_inches='tight')695plt.close()696\end{pycode}697698\begin{figure}[htbp]699\centering700\includegraphics[width=\textwidth]{rsa_implementation_analysis.pdf}701\caption{RSA implementation considerations: (left) timing variations across different702ciphertext inputs showing potential side-channel vulnerability with operation counts varying703by \py{max(operation_counts) - min(operation_counts)} operations, demonstrating why constant-time704implementations are essential; (center) textbook RSA malleability illustrated where705$E(m_1) \cdot E(m_2) = E(m_1 \cdot m_2)$, showing why padding schemes like OAEP are mandatory706for real-world security; (right) performance scaling demonstrating that key generation time707grows superlinearly with key size, with 2048-bit keys requiring \py{f"{generation_times[2]/generation_times[0]:.1f}"}x708longer than 512-bit keys.}709\label{fig:implementation}710\end{figure}711712The malleability demonstration reveals a critical weakness of "textbook RSA" without padding:713an attacker can manipulate ciphertexts arithmetically to produce valid encryptions of related714plaintexts. For our example, $E(m_1) \times E(m_2) \bmod n = E(m_1 \times m_2 \bmod n)$, where715$m_1 = \py{m1}$, $m_2 = \py{m2}$, and the product decrypts to $\py{m_product} = \py{expected_product}$.716This is why modern RSA implementations mandate padding schemes like OAEP (Optimal Asymmetric717Encryption Padding) that randomize plaintexts before encryption.718719\section{Results}720721\subsection{Key Generation Statistics}722723\begin{pycode}724print(r"\begin{table}[htbp]")725print(r"\centering")726print(r"\caption{RSA Key Generation Results Across Multiple Key Sizes}")727print(r"\begin{tabular}{lcccc}")728print(r"\toprule")729print(r"Key Size & Modulus Bits & $\phi(n)$ Bits & Public Exp $e$ & Gen Time (s) \\")730print(r"\midrule")731732for key_size in key_sizes:733k = keys[key_size]734n_bits = k['n'].bit_length()735phi_bits = k['phi_n'].bit_length()736print(f"{key_size}-bit & {n_bits} & {phi_bits} & {k['e']} & {k['gen_time']:.4f} \\\\")737738print(r"\bottomrule")739print(r"\end{tabular}")740print(r"\label{tab:keygen}")741print(r"\end{table}")742\end{pycode}743744\subsection{Encryption Performance Metrics}745746\begin{pycode}747print(r"\begin{table}[htbp]")748print(r"\centering")749print(r"\caption{Cipher Operation Performance for 1024-bit RSA Keys}")750print(r"\begin{tabular}{lcccc}")751print(r"\toprule")752print(r"Message & Plaintext Bits & Ciphertext Bits & Enc Time (ms) & Dec Time (ms) \\")753print(r"\midrule")754755for i, m in enumerate(messages):756m_bits = m.bit_length()757c_bits = ciphertexts_1024[i].bit_length()758enc_ms = encryption_times[i] * 1000759dec_ms = decryption_times[i] * 1000760print(f"{m} & {m_bits} & {c_bits} & {enc_ms:.4f} & {dec_ms:.4f} \\\\")761762print(r"\midrule")763avg_enc = np.mean(encryption_times) * 1000764avg_dec = np.mean(decryption_times) * 1000765print(f"Average & --- & --- & {avg_enc:.4f} & {avg_dec:.4f} \\\\")766print(r"\bottomrule")767print(r"\end{tabular}")768print(r"\label{tab:performance}")769print(r"\end{table}")770\end{pycode}771772\section{Discussion}773774\subsection{Practical Deployment Considerations}775776While RSA provides strong mathematical security when properly implemented, several practical777considerations affect real-world deployment:778779\begin{enumerate}780\item \textbf{Hybrid Cryptography}: RSA's computational cost and message size limitations make781it unsuitable for bulk data encryption. Production systems use hybrid schemes where RSA encrypts782a symmetric key (AES-256), which then encrypts the actual data.783784\item \textbf{Padding Schemes}: As demonstrated by the malleability attack, textbook RSA must785never be used in practice. OAEP padding introduces randomization that prevents deterministic786encryption and chosen-ciphertext attacks.787788\item \textbf{Key Management}: Private keys must be stored securely (hardware security modules789for high-value applications), and key rotation schedules should account for advancing790computational capabilities.791792\item \textbf{Post-Quantum Readiness}: While RSA remains secure against classical computers,793Shor's algorithm enables polynomial-time factorization on quantum computers. Organizations should794monitor NIST's post-quantum standardization effort for future migration paths.795\end{enumerate}796797\subsection{Performance Optimization Strategies}798799Our implementation demonstrates baseline RSA performance, but production systems employ several800optimizations:801802\begin{itemize}803\item \textbf{Chinese Remainder Theorem (CRT)}: Decryption can be accelerated by computing804$m_p = c^d \bmod p$ and $m_q = c^d \bmod q$ separately, then recombining via CRT, achieving805approximately 4x speedup.806807\item \textbf{Montgomery Multiplication}: Specialized modular multiplication algorithms reduce808the constant factor in exponentiation complexity.809810\item \textbf{Multi-Prime RSA}: Using more than two primes can improve decryption performance811at the cost of slightly reduced security margins.812\end{itemize}813814\section{Conclusions}815816This comprehensive analysis of RSA encryption demonstrates the complete lifecycle of the817cryptosystem from key generation through cipher operations to security considerations. Our818implementation generated keys ranging from 512-bit (educational use) to 2048-bit (current819production standard), with generation times scaling from \py{f"{generation_times[0]:.4f}"}820seconds to \py{f"{generation_times[2]:.4f}"} seconds. Encryption and decryption testing on8211024-bit keys revealed the expected performance asymmetry, with public-key encryption averaging822\py{f"{avg_enc:.4f}"} milliseconds versus private-key decryption at \py{f"{avg_dec:.4f}"}823milliseconds.824825Security analysis confirmed the exponential growth of factorization complexity, validating the826computational intractability assumption underlying RSA's security model. Side-channel analysis827demonstrated timing variations that could leak private key information in naive implementations,828highlighting the importance of constant-time algorithms and padding schemes in production829cryptographic libraries.830831For practical deployment, organizations should use minimum 2048-bit keys with OAEP padding,832implement constant-time operations to resist side-channel attacks, employ hybrid encryption833for bulk data, and maintain awareness of post-quantum cryptography developments as quantum834computing capabilities advance.835836\section*{References}837838\begin{enumerate}839\item Rivest, R. L., Shamir, A., \& Adleman, L. (1978). A method for obtaining digital signatures840and public-key cryptosystems. \textit{Communications of the ACM}, 21(2), 120-126.841842\item Boneh, D. (1999). Twenty years of attacks on the RSA cryptosystem. \textit{Notices of the843American Mathematical Society}, 46(2), 203-213.844845\item Lenstra, A. K., \& Verheul, E. R. (2001). Selecting cryptographic key sizes.846\textit{Journal of Cryptology}, 14(4), 255-293.847848\item Kocher, P. C. (1996). Timing attacks on implementations of Diffie-Hellman, RSA, DSS, and849other systems. In \textit{Advances in Cryptology—CRYPTO'96} (pp. 104-113).850851\item Bellare, M., \& Rogaway, P. (1995). Optimal asymmetric encryption. In \textit{Advances in852Cryptology—EUROCRYPT'94} (pp. 92-111).853854\item NIST Special Publication 800-57 Part 1 Rev. 5 (2020). \textit{Recommendation for Key855Management: Part 1 – General}.856857\item Barker, E., \& Roginsky, A. (2019). Transitioning the use of cryptographic algorithms and858key lengths. NIST Special Publication 800-131A Rev. 2.859860\item Montgomery, P. L. (1985). Modular multiplication without trial division.861\textit{Mathematics of Computation}, 44(170), 519-521.862863\item Quisquater, J. J., \& Couvreur, C. (1982). Fast decipherment algorithm for RSA public-key864cryptosystem. \textit{Electronics Letters}, 18(21), 905-907.865866\item Shor, P. W. (1997). Polynomial-time algorithms for prime factorization and discrete867logarithms on a quantum computer. \textit{SIAM Journal on Computing}, 26(5), 1484-1509.868869\item Rabin, M. O. (1980). Probabilistic algorithm for testing primality.870\textit{Journal of Number Theory}, 12(1), 128-138.871872\item Menezes, A. J., Van Oorschot, P. C., \& Vanstone, S. A. (2018). \textit{Handbook of873Applied Cryptography}. CRC Press.874875\item Ferguson, N., Schneier, B., \& Kohno, T. (2010). \textit{Cryptography Engineering: Design876Principles and Practical Applications}. Wiley.877878\item Kaliski, B. (2003). PKCS\# 1: RSA Cryptography Specifications Version 2.1.879\textit{RFC 3447}.880881\item Chen, L., et al. (2016). Report on post-quantum cryptography. NIST Interagency Report 8105.882\end{enumerate}883884\end{document}885886887