RSAの暗号・復号をアプリ上でやってみた。
開発環境:Xcode9.4.1
1.アプリの概要(画面)
「素数1」、「素数2」、「素数3」のテキストフィールドに鍵の生成に必要な素数を入力する。
アプリを起動した時と、「生成」ボタンを押した時に素数が自動で生成される。
「暗号化」ボタンを押すと暗号、「復号化」ボタンを押すと復号する。
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みたいに巨大な数値を取り扱えないのが残念だった。