Created
March 23, 2021 13:17
-
-
Save atierian/dd12aca9e0c289688518d9175eb34e3a to your computer and use it in GitHub Desktop.
Basic example showing how RSA encryption works
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// Select two prime numbers `p` and `q` (generally very large numbers, but using small numbers due to limitations of UInt) | |
| let p: UInt = 5 | |
| let q: UInt = 7 | |
| /// `n` is the product of `p` and `q` | |
| let n: UInt = p * q //35 | |
| /// `r` is `(p - 1) * (q - 1)` | |
| let r: UInt = (p-1) * (q-1) //24 | |
| /// Determine potential `k` candidates, where each potential `k` is `r * x + 1` | |
| let candidates = (1...30).map { r * $0 + 1 } | |
| /// Find a `k` that factors to `e` and `d` where both `e` and `d` are relatively prime to `n` and `e * d == 1 % r` | |
| func generateKeys(from k: UInt) -> Keys? { | |
| for eCandidate in 3...k/3 where k % eCandidate == 0 { | |
| let dCandidate = k / eCandidate | |
| guard areCoprime(eCandidate, r), | |
| areCoprime(dCandidate, r) | |
| else { continue } | |
| return Keys(e: eCandidate, d: dCandidate) | |
| } | |
| return nil | |
| } | |
| func areCoprime(_ m: UInt, _ n: UInt) -> Bool { | |
| var a: UInt = 0 | |
| var b: UInt = max(m, n) | |
| var r: UInt = min(m, n) | |
| while r != 0 { | |
| a = b | |
| b = r | |
| r = a % b | |
| } | |
| return b == 1 | |
| } | |
| /// Key contains properties `e` and `d`, where `e` is the public key and `d` is the private key | |
| let keys = candidates.compactMap { generateKeys(from: $0) }.first //e = 5, d = 5 | |
| /// Message to encrypt | |
| let message: [UInt] = [7, 4, 5, 12, 22, 25, 33, 1, 14, 34] | |
| /// Enrypt message with `message^e % n` | |
| func encrypt(message: [UInt], e: UInt, n: UInt) -> [UInt8] { | |
| message.map { | |
| UInt8( | |
| UInt( pow(Double($0), Double(e) ) | |
| ) % n | |
| ) | |
| } | |
| } | |
| /// Encrypted message | |
| let encrypted = encrypt(message: message, e: keys!.e, n: n) // [7, 9, 10, 17, 22, 30, 3, 1, 14, 34] | |
| /// Decrypt encrypted message with `encrypted^d % n` | |
| func decrypt(_ encrypted: [UInt8], d: UInt, n: UInt) -> [UInt8] { | |
| encrypted.map { | |
| UInt8( | |
| UInt( pow(Double($0), Double(d) ) | |
| ) % n | |
| ) | |
| } | |
| } | |
| /// Decrypted message | |
| let decrypted = decrypt(encrypted, d: keys!.d, n: n) // [7, 4, 5, 12, 22, 25, 33, 1, 14, 34] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment