Skip to content

Instantly share code, notes, and snippets.

@soheilbm
Forked from alskipp/encrypt_xor1.swift
Created February 11, 2016 17:28
Show Gist options
  • Save soheilbm/4a207a2e699c4440b94e to your computer and use it in GitHub Desktop.
Save soheilbm/4a207a2e699c4440b94e to your computer and use it in GitHub Desktop.
Swift encrypt/decrypt string using XOR
import Foundation
extension Character {
func utf8() -> UInt8 {
let utf8 = String(self).utf8
return utf8[utf8.startIndex]
}
}
func encrypt(c:Character, key:Character) -> String {
let byte = [c.utf8() ^ key.utf8()]
return String(bytes: byte, encoding: NSUTF8StringEncoding)! // forced unwrapping alert!
}
func encrypt(message:String, #key:String) -> String {
return reduce(Zip2(message, key), "") { $0 + encrypt($1) }
}
let message = "Hello world!"
let secretKey = "(:.,?P!9@PAz" // really should be randomly generated!
let encryptedMessage = encrypt(message, key: secretKey) // > "`_B@PpVV2<%["
let decryptedMessage = encrypt(encryptedMessage, key: secretKey) // > "Hello world!"
/* (Requires Swift 1.2)
In the version above you'll notice that there's use of forced Optional unwrapping.
This is potentially hazardous. Here's a version that deals with Optional values safely.
Having to 'reduce' Optional Strings adds significant complexity.
Below, I've shown 2 ways of dealing with this (Monadic bind & 'if let' syntax).
*/
import Foundation
// Monadic bind for Optionals
infix operator >>= {associativity left}
func >>= <A,B> (m: A?, f: A -> B?) -> B? {
if let x = m {return f(x)}
return .None
}
extension Character {
func utf8() -> UInt8 {
let utf8 = String(self).utf8
return utf8[utf8.startIndex]
}
}
func encrypt(key:Character, c:Character) -> String? {
let byte = [key.utf8() ^ c.utf8()]
return String(bytes: byte, encoding: NSUTF8StringEncoding)
}
// Curried func for convenient use with map
func encryptKey(key:String)(message:String) -> String? {
return reduce(zip(key, message), Optional("")) { str, c in str >>= { s in encrypt(c).map {s + $0} }}
}
let message = "Hello world!"
let secretKey = "(:.,?P!9@PAz" // really should be randomly generated!
let encryptedMessage = encryptKey(secretKey)(message: message) // > .Some("`_B@PpVV2<%[")
// As the encryptKey func is curried it can be passed directly to map
let decryptedMessage = encryptedMessage.map(encryptKey(secretKey)) // > .Some("Hello world!")
/* here's how the encrypt function would look like using 'if let' syntax
func encryptKey_if_let(key:String)(message:String) -> String? {
return reduce(zip(key, message), Optional("")) { if let str = $0, c = encrypt($1) {
return str + c
} else {
return .None}
}
}
*/
@pexavc
Copy link

pexavc commented May 15, 2023

Update for xor1, to work in modern Swift.

XCode 14.2
Swift 5 / swift-tools: 5.7

func encrypt(c: Character, key: Character) -> String? {
    let byte = [c.utf8() ^ key.utf8()]
    return String(bytes: byte, encoding: .utf8)
}
 
func encryptDecrypt(message: String, key:String) -> String {
    return zip(message, key).compactMap { encrypt(c: $0.0, key: $0.1) }.joined()
}

Be aware I used compactMap above. If there are indeed nil values, utf8 encoding failed somewhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment