2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SwiftでRSAを実装してみた

Last updated at Posted at 2018-07-24

RSAの暗号・復号をアプリ上でやってみた。
開発環境:Xcode9.4.1

1.アプリの概要(画面)

「素数1」、「素数2」、「素数3」のテキストフィールドに鍵の生成に必要な素数を入力する。
アプリを起動した時と、「生成」ボタンを押した時に素数が自動で生成される。
「暗号化」ボタンを押すと暗号、「復号化」ボタンを押すと復号する。
スクリーンショット 2018-07-24 16.04.16.png

2.コードを書いてみる

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の鍵を生成して暗号・復号をしている。
素数の判定はミラー–ラビン素数判定法を使っている。
コードはこちらを参考にした。
Pythonみたいに巨大な数値を取り扱えないのが残念だった。

3.実行してみる

こんな感じになった。
スクリーンショット 2018-07-24 17.02.12.png
桁数少ないから実行時間はかからない。

2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?