Skip to content

Instantly share code, notes, and snippets.

@devpolant
Last active February 20, 2017 22:43
Show Gist options
  • Save devpolant/a1530e4bdce64cc609514d5cf0368150 to your computer and use it in GitHub Desktop.
Save devpolant/a1530e4bdce64cc609514d5cf0368150 to your computer and use it in GitHub Desktop.
Cryptography
import Foundation
// MARK: - Text + Statistic
public extension Character {
var isWhiteSpace: Bool {
return self == Character(" ")
}
}
struct Letter: CustomStringConvertible {
var char: Character
var count: Int
var percent: Double
var description: String {
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
let percentage = formatter.string(for: percent * 100)!
return "\(char): count=\(count), \(percentage)%"
}
}
public func analyze(text: String, ofType textType: String) {
print("========== \(textType) ==========")
var dictionary = [Character: Int]()
var nonWhiteScapeCount = 0
for char in text.lowercased().characters {
guard !char.isWhiteSpace else {
continue
}
nonWhiteScapeCount += 1
let count = dictionary[char] ?? 0
dictionary[char] = count + 1
}
let sortedResult = dictionary.sorted { first, second -> Bool in
if first.value != second.value {
return first.value > second.value
}
return first.key < second.key
}
let statistic = sortedResult.map { pair -> Letter in
return Letter(char: pair.key,
count: pair.value,
percent: Double(pair.value) / Double(nonWhiteScapeCount))
}
print(statistic)
}
//MARK: - XOR
public func testXOR() {
let key = "12345"
let inputText = "Some test text"
let encrypted = xor(string: inputText, key: key)
let decrypted = xor(string: encrypted!, key: key)
print("encrypted: '\(encrypted!)', key: \(key)")
print("decrypted: '\(decrypted!)', key: \(key)")
}
func xor(string: String, key: String) -> String? {
let utf8Key = key.utf8
let bytes = string.utf8.enumerated().map {
$1 ^ utf8Key[utf8Key.index(utf8Key.startIndex, offsetBy: $0 % utf8Key.count)]
}
return String(bytes: bytes, encoding: String.Encoding.utf8)
}
func xor (a: Int, b: Int) -> Int {
return (~a & b) | (~b & a)
}
// MARK: - Cesar
public func testCesar() {
do {
let key = 5
let encrypted = try cesarEncrypt(text: "this is a test message", alphabet: .english, key: key)
print("encrypted: '\(encrypted)', key: \(key)")
let decrypted = try cesarDecrypt(text: encrypted, alphabet: .english, key: key)
print("decrypted: '\(decrypted)', key: \(key)")
} catch {
print(error)
}
}
public enum Alphabet {
case english
public var length: Int {
switch self {
case .english:
return 26
}
}
public var characters: [Character] {
return "abcdefghijklmnopqrstuvwxyz".characters.flatMap { $0 }
}
}
public enum CesarError: Error {
case encryptionFailed(cause: String)
}
public func cesarEncrypt(text: String, alphabet: Alphabet, key: Int) throws -> String {
var result = ""
for char in text.lowercased().characters {
guard let index = alphabet.characters.index(of: char) else {
if char.isWhiteSpace {
result.append(char)
continue
}
throw CesarError.encryptionFailed(cause: "Unrecognized symbol in alphabet")
}
let encryptedChar = alphabet.characters[(index + key) % alphabet.length]
result.append(encryptedChar)
}
return result
}
public func cesarDecrypt(text: String, alphabet: Alphabet, key: Int) throws -> String {
var result = ""
for char in text.lowercased().characters {
guard let index = alphabet.characters.index(of: char) else {
if char.isWhiteSpace {
result.append(char)
continue
}
throw CesarError.encryptionFailed(cause: "Unrecognized symbol in alphabet")
}
let encryptedChar = alphabet.characters[(index - key >= 0 ? index - key : alphabet.length + index - key) % alphabet.length]
result.append(encryptedChar)
}
return result
}
// MARK: - Vernam
public func testVernam() {
let text = "This is a test message"
let cipher = VernamCipher()
let encrypted = cipher.encrypt(text: text)
let decrypted = cipher.decrypt(text: encrypted.text, key: encrypted.key)
print("Original: \(text)")
print("Encrypted: \(encrypted.text)")
print("Decrypted: \(decrypted)")
}
class VernamCipher {
func encrypt(text: String) -> (text: String, key: [Int]) {
let text = text.lowercased()
let key = self.key(count: text.characters.count)
let map = self.map()
var output = String()
for (index, character) in text.characters.enumerated() {
if character == " " {
output.append(character)
} else if let letterIndex = map.forward[String(character)] {
let keyIndex = key[index]
let outputIndex = (letterIndex + keyIndex + map.lastCharacterIndex) % map.lastCharacterIndex
if let outputCharacter = map.reversed[outputIndex] {
output.append(outputCharacter)
}
}
}
return (text: output.uppercased(), key: key)
}
func decrypt(text: String, key:[Int]) -> String {
let text = text.lowercased()
let map = self.map()
var output = String()
for (index, character) in text.characters.enumerated() {
if character == " " {
output.append(character)
} else if let letterIndex = map.forward[String(character)] {
let keyIndex = key[index]
let outputIndex = (letterIndex - keyIndex + map.lastCharacterIndex) % map.lastCharacterIndex
if let outputCharacter = map.reversed[outputIndex] {
output.append(outputCharacter)
}
}
}
return output
}
let alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
func key(count: Int) -> [Int] {
var key = [Int]()
for _ in 0..<count {
key.append(Int(arc4random() % 26))
}
return key
}
private func map() -> (forward: [String : Int], reversed: [Int : String], lastCharacterIndex: Int) {
var forward = [String : Int]()
var reversed = [Int : String]()
var lastCharacterIndex = 0
for (index, letter) in self.alphabet.enumerated() {
forward[letter] = index
reversed[index] = letter
lastCharacterIndex = index
}
return (forward: forward, reversed: reversed, lastCharacterIndex: lastCharacterIndex)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment