SwiftでRSAを実装してみた

RSAの暗号・復号をアプリ上でやってみた。
開発環境：Xcode9.4.1
#1.アプリの概要(画面)
「素数１」、「素数２」、「素数３」のテキストフィールドに鍵の生成に必要な素数を入力する。
アプリを起動した時と、「生成」ボタンを押した時に素数が自動で生成される。
「暗号化」ボタンを押すと暗号、「復号化」ボタンを押すと復号する。
<img width="1440" alt="スクリーンショット 2018-07-24 16.04.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/274361/9e0e5672-a80d-1f02-ede8-fec4cc1ba2ce.png">
#2.コードを書いてみる
```swift:ViewController.swift
import UIKit
import Foundation

class ViewController: UIViewController,UITextFieldDelegate {
    
    var p:Int64 = 0
    var q:Int64 = 0
    var r:Int64 = 0
    
    var sample:String = "11111"
    
    @IBOutlet weak var textView1: UITextView!
    @IBOutlet weak var textView2: UITextView!
    
    @IBOutlet weak var textField1: UITextField!
    @IBOutlet weak var textField2: UITextField!
    @IBOutlet weak var textField3: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        textField1.delegate = self
        textField2.delegate = self
        textField3.delegate = self
        textView1.text = ""
        textView2.text = ""
        p = PrimeNumber(bit: 15)
        q = PrimeNumber(bit: 15)
        r = PrimeNumber(bit: 15)
        while true {
            if CheckCrypt(p: p, q: q, r: r) {
                break
            } else {
                p = PrimeNumber(bit: 15)
                q = PrimeNumber(bit: 15)
                r = PrimeNumber(bit: 15)
            }
        }
        textField1.text = String(p)
        textField2.text = String(q)
        textField3.text = String(r)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    //暗号化ボタンを押した時の処理
    @IBAction func Encrypt(_ sender: UIButton) {
        let pq:Int64 = p * q
        let crypt:Int64 = Mod(num: Int64(textView1.text)!, exp: Int64(textField3.text!)!, a: pq)
        textView2.text = String(crypt)
    }
    
    //復号化ボタンを押した時の処理
    @IBAction func Decrypt(_ sender: UIButton) {
        let key:Int64 = privateKey(a: Int64(textField1.text!)!, b: Int64(textField2.text!)!, c: Int64(textField3.text!)!)
        let pq:Int64 = p * q
        let crypt:Int64 = Mod(num: Int64(textView2.text)!, exp: key, a: pq)
        textView1.text = String(crypt)
    }
    
    //生成ボタンを押した時の処理
    @IBAction func Generate(_ sender: UIButton) {
        p = PrimeNumber(bit: 15)
        q = PrimeNumber(bit: 15)
        r = PrimeNumber(bit: 15)
        while true {
            if CheckCrypt(p: p, q: q, r: r) {
                break
            } else {
                p = PrimeNumber(bit: 15)
                q = PrimeNumber(bit: 15)
                r = PrimeNumber(bit: 15)
            }
        }
        textField1.text = String(p)
        textField2.text = String(q)
        textField3.text = String(r)
    }
    
    //素数生成
    func PrimeNumber(bit: Int) -> Int64 {
        var num:Int64 = 0
        while true {
            num = GetNumber(bitLen: bit)
            if primeCheck(num: num) {
                break
            }
        }
        return Int64(num)
    }
    
    //乱数生成
    func GetNumber(bitLen: Int) -> Int64 {
        var rand:[Int] = []
        for _ in 0..<bitLen - 2 {
            rand.append(Int(arc4random_uniform(2)))
        }
        var ret:Int64 = 1
        for item in rand {
            ret = ret * 2 + Int64(item)
        }
        return ret * 2 + 1
    }
    
    //素数判定
    func primeCheck(num: Int64) -> Bool {
        if num == 1 {
            return false
        }
        if num == 2 {
            return true
        }
        if num % 2 == 0 {
            return false
        }
        var d:Int64 = num - 1
        var s:Int = 0
        while d % 2 != 0 {
            d /= 2
            s += 1
        }
        var r:[Int64] = []
        for _ in 0..<100 {
            r.append(Int64(arc4random_uniform(UInt32(num) - 2)) + 1)
        }
        for a in r {
            if Mod(num: a, exp: d, a: num) != 1 {
                var pl:[Int64] = []
                for i in 0..<s {
                    pl[i] = Int64(pow(2.0, Double(i))) * d
                }
                var flag:Bool = true
                for p in pl {
                    if Mod(num: a, exp: p, a: num) == 1 {
                        flag = false
                        break
                    }
                }
                if flag {
                    return false
                }
            }
        }
        return true
    }
    
    //最小公倍数の計算
    func Lcm(a: Int64, b: Int64) -> Int64 {
        var i:Int64 = a
        var j:Int64 = b
        var c:Int64
        let ij:Int64 = i * j
        while i % j != 0 {
            c = j
            j = i % j
            i = c
        }
        return ij / j
    }
    
    //べき乗計算
    func Mod(num: Int64, exp: Int64, a: Int64) -> Int64 {
        var res:Int64 = 1
        var number:Int64 = num
        var e:Int64 = exp
        while e > 0 {
            if (e & 1) > 0 {
                res = (res * number) % a
            }
            number = (number * number) % a
            e >>= 1
        }
        return res
    }
    
    //秘密鍵生成
    func privateKey(a: Int64, b: Int64, c: Int64) -> Int64 {
        let lcm = Lcm(a: a - 1, b: b - 1)
        var a1:Int64 = 1
        var b1:Int64 = 0
        var c1:Int64 = lcm
        var a2:Int64 = 0
        var b2:Int64 = 1
        var c2:Int64 = c
        var a3:Int64
        var b3:Int64
        var c3:Int64
        var d:Int64 = 1
        while c2 > 0 {
            d = Int64(c1 / c2)
            a3 = a1 - d * a2
            b3 = b1 - d * b2
            c3 = c1 - d * c2
            a1 = a2
            b1 = b2
            c1 = c2
            a2 = a3
            b2 = b3
            c2 = c3
        }
        return (a1 > b1) ? a1 : b1
    }
    
    //復号できるか確認
    func CheckCrypt(p: Int64, q: Int64, r: Int64) -> Bool {
        let pq:Int64 = p * q
        var crypt:Int64 = Mod(num: Int64(sample)!, exp: r, a: pq)
        let key:Int64 = privateKey(a: p, b: q, c: r)
        crypt = Mod(num: crypt, exp: key, a: pq)
        if String(crypt) == sample {
            return true
        }
        return false
    }
    
    //キーボードのreturnキー押した時の処理
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}
```
Swiftの数値型の範囲の都合で30bitの鍵を生成して暗号・復号をしている。
素数の判定は[ミラー–ラビン素数判定法](https://ja.wikipedia.org/wiki/ミラー–ラビン素数判定法)を使っている。
コードは[こちら](https://qiita.com/moajo/items/0ea9043f9688b05fa39a)を参考にした。
Pythonみたいに巨大な数値を取り扱えないのが残念だった。
#3.実行してみる
こんな感じになった。
<img width="1440" alt="スクリーンショット 2018-07-24 17.02.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/274361/410485db-ea6b-c901-ac33-fa464c549d85.png">
桁数少ないから実行時間はかからない。