From 66212f78ac2baa80c5b3833f0bff816b2cd37063 Mon Sep 17 00:00:00 2001 From: Yan Date: Mon, 30 Sep 2024 02:57:07 -0700 Subject: [PATCH] descriptiveness --- cryptography/level-6/DESCRIPTION.md | 6 +++--- cryptography/level-7/DESCRIPTION.md | 29 ++++++++++++++++++++++++++++- cryptography/level-7/run | 6 +++--- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/cryptography/level-6/DESCRIPTION.md b/cryptography/level-6/DESCRIPTION.md index 4d1cf11..041eef3 100644 --- a/cryptography/level-6/DESCRIPTION.md +++ b/cryptography/level-6/DESCRIPTION.md @@ -12,15 +12,15 @@ Let's take it step by step: 1. First, Alice and Bob agree on a large prime number `p` to define their Finite Field (e.g., all further operations occur _modulo `p`_: a context where numbers go from `0` to `p-1`, and then loop around), along with a _root_ `g`, and exchange them in the open, content to let Eve see them. 2. Then, Alice and Bob each generate a _secret_ number (`a` for Alice's and `b` for Bob's). These numbers are never shared. -3. Alice computes `A = (g ** a) % p` (`g` to the `a` power modulo `p`) and Bob computes `B = (g ** b) % p`. +3. Alice computes `A = (g ** a) mod p` (`g` to the `a` power modulo `p`) and Bob computes `B = (g ** b) mod p`. Alice and Bob exchange `A` and `B` in the open. 4. At this point, Eve will have `p`, `g`, `A`, and `B`, but will be unable to recover `a` or `b`. If it wasn't for the finite field, recovering `a` and `b` would be trivial via a logarithm-base-`g`: `log_g(A) == a` and `log_g(B) == b`. However, this does not work in a Finite Field under a modulo because, conceptually, we have no efficient way to determine how many times the `g ** a` computation "looped around" from `p-1` to `0`, and this is needed to compute the logarithm. This logarithm-in-a-finite-field problem is called the [Discrete Logarithm](https://en.wikipedia.org/wiki/Discrete_logarithm), and there is no efficient way to solve this without using a quantum computer. Quantum computers' ability to solve this problem is the most immediate thing that makes them so dangerous to cryptography. -5. Alice calculates `s = (B ** a) % p`, and since `B` was `(g ** b) % p`, this results in `s = ((g ** b) ** a) % p` or, applying middle school math, `s = (g ** (b*a)) % p`. - Bob calculates `s = (A ** b) % p`, and since `A` was `(g ** a) % p`, this results in `s = (g ** (a*b)) % p`. Since `a*b == b*a`, the `s` values computed by both Bob and Alice are equal! +5. Alice calculates `s = (B ** a) mod p`, and since `B` was `(g ** b) mod p`, this results in `s = ((g ** b) ** a) mod p` or, applying middle school math, `s = (g ** (b*a)) mod p`. + Bob calculates `s = (A ** b) mod p`, and since `A` was `(g ** a) mod p`, this results in `s = (g ** (a*b)) mod p`. Since `a*b == b*a`, the `s` values computed by both Bob and Alice are equal! 6. Eve _cannot_ compute `s` because Eve lacks `a` or `b`. Eve could compute `A ** B == g ** a ** g ** b`, which reduces to something like `g ** (a*(g**b))` and doesn't get Eve any closer to `s`! Eve could also compute `A * B == (g ** a) * (g ** b) == g ** (a+b)`, but again, this is not the `s == g ** (a*b)` that Bob and Alice arrived at. diff --git a/cryptography/level-7/DESCRIPTION.md b/cryptography/level-7/DESCRIPTION.md index 8051aba..337c465 100644 --- a/cryptography/level-7/DESCRIPTION.md +++ b/cryptography/level-7/DESCRIPTION.md @@ -1,2 +1,29 @@ +Diffie-Hellman allow Alice and Bob to generate a single (but uncontrolled) shared secret with no pre-shared secret information. +Next, we'll learn about another cryptosystem, [RSA (Rivest–Shamir–Adleman)](https://en.wikipedia.org/wiki/RSA_(cryptosystem)), that allows Alice and Bob to generate arbitrary amounts of controlled messages, with no pre-shared secret information! + +RSA uses a clever interaction of modular exponentiation (which you've experienced in DH) and [Euler's Theorem](https://en.wikipedia.org/wiki/Euler%27s_theorem) to give Bob or Alice _asymmetric_ control over an entire finite field. +Alice generates two primes, `p` and `q`, _and keeps them secret_, then multiplies them to create `n = p*q`, which Alice publishes to define a Finite Field modulo `n`. +Euler's Theorem and knowledge of `p` and `q` gives Alice, _and only Alice_, full abilities within this specific field (which is a difference from DH, where all actors have equal capabilities in the field!). + +Euler's Theorem tells us that operations _in an exponent_ of a field modulo `p*q` (e.g., the `e*d` of `m**(e*d) mod n`) take place in the field of `(p-1)*(q-1)`. +The _why_ of this theorem is some advanced math stuff that, to be honest, few people understand, but the results are interesting. +Computing `(p-1)*(q-1)` is trivial for Alice (armed with knowledge of `p` and `q`) but impossible to anyone else (assuming that `p` and `q` are large), because the human race lacks an efficient algorithm to factor products of large prime numbers! + +Recall that `e*d` in the exponent of `m**(e*d) mod n`? +For any `e`, knowing `(p-q)*(q-1)` allows Alice to compute a `d` such that `e*d == 1`. +While this seems silly, it is the core of RSA. +Alice chooses a number `e` (typically fairly small to reduce computation costs, but not too small to cause certain security issues) and computes the corresponding multiplicative inverse `d`. +This leads to encryption of plaintext `m` (`m**e mod n == c`) and decryption! `c**d mod n == (m**e)**d mod n == m**(e*d) mod n == m**1 mod n == m`. +Rather than DH's single and uncontrolled `s`, RSA messages `m` can be chosen arbitrarily (up to the size of `n`, as the field is unable to represent larger numbers). + +RSA is _asymmetric_. +Alice shares `n` and `e` as the public key, and keeps `d` as the private key. +Knowing `n` and `e`, Bob can encrypt messages and send them to Alice, and only Alice can decrypt them. +Since `e*d == d*e`, Alice _can_ use `d` to encrypt messages, but _anyone_ can decrypt them, since `e` is public. +This might sound silly, but it is useful for, e.g., attesting that a given message could come only from Alice, since knowledge of `d` is required for this. + +To respond to Bob, Alice would need Bob's own public key, which would be _Bob's_ `n` (different from Alice's `n`, using Bob's own secret `p` and `q`!) and `e` (which is typically the same smallest-safe value, currently `65537` but subject to change as new attacks are found). + In this challenge you will decrypt a secret encrypted with RSA (Rivest–Shamir–Adleman). -You will be provided with both the public key and private key. +You will be provided with both the public key and private key this time, to get a feel for how all this works. +Go for it! diff --git a/cryptography/level-7/run b/cryptography/level-7/run index 10ead36..67aa922 100755 --- a/cryptography/level-7/run +++ b/cryptography/level-7/run @@ -7,9 +7,9 @@ flag = open("/flag", "rb").read() assert len(flag) <= 256 key = RSA.generate(2048) -print(f"e = {key.e:#x}") -print(f"d = {key.d:#x}") -print(f"n = {key.n:#x}") +print(f"(public) n = {key.n:#x}") +print(f"(public) e = {key.e:#x}") +print(f"(private) d = {key.d:#x}") ciphertext = pow(int.from_bytes(flag, "little"), key.e, key.n).to_bytes(256, "little") print(f"Flag Ciphertext (b64): {b64encode(ciphertext).decode()}")