Swift Simple Xor Encryption

Swift Simple XOR Encryption

I would propose an extension to String like this.

extension String {
func encodeWithXorByte(key: UInt8) -> String {
return String(bytes: map(self.utf8){$0 ^ key}, encoding: NSUTF8StringEncoding)!
}

From the inside out,

  1. The call to self.utf8 creates a byte array, [UInt8], from the string
  2. map() is called on each element and XOR'ed with the key value
  3. A new String object is created from the XOR'ed byte array

Here is my Playground screen capture.
Sample Image

UPDATED: For Swift 2.0

extension String {
func encodeWithXorByte(key: UInt8) -> String {
return String(bytes: self.utf8.map{$0 ^ key}, encoding: NSUTF8StringEncoding) ?? ""
}
}

XOR Encryption in Swift IOS

Disclaimer: As explained in the comments using this kind of bit manipulation on UTF8 strings is unsafe and will not work as expected for arbitrary inputs.

I'm actually not sure whether the original Objective-C code does what you want. sizeof(key) is the size of the memory address of a char pointer (8 on my platform) and not the length of the UTF8 array. On top, sizeof(char) should always be 1. You probably want to use strlen instead.

Anyways, the equivalent of the (corrected) Objective-C code in Swift 2 could like this

func encryptDecrypt(input: String, staticKey: String) -> String? {
let key = staticKey.utf8
let bytes = input.utf8.enumerate().map({
$1 ^ key[key.startIndex.advancedBy($0 % key.count)]
})
return String(bytes: bytes, encoding: NSUTF8StringEncoding)
}

The test snippet

let key = "12345"
let string = "abcdefghijklmnopqrstuvwxyz"

let encrypted = encryptDecrypt(string, staticKey: key)!
let decrypted = encryptDecrypt(encrypted, staticKey: key)!

print(string)
print(encrypted)
print(decrypted)

will print out

abcdefghijklmnopqrstuvwxyz
PPPPPWU[]_Z^^ZZACAGADDDLLK
abcdefghijklmnopqrstuvwxyz

For Swift 1.2 you'll have to make a couple of small adaptions:

func encryptDecrypt(input: String, staticKey: String) -> String? {
let key = staticKey.utf8
let keyLength = distance(key.startIndex, key.endIndex)
let bytes = map(enumerate(input.utf8)) {
$1 ^ key[advance(key.startIndex, $0 % keyLength)]
}
return String(bytes: bytes, encoding: NSUTF8StringEncoding)
}

Update: The following snippet is closer to the original Objective-C code and works for arbitrary strings:

func encryptDecrypt(input: NSString, staticKey: NSString) -> NSString? {
let chars = (0..<input.length).map({
input.characterAtIndex($0) ^ staticKey.characterAtIndex($0 % staticKey.length)
})
return NSString(characters: chars, length: chars.count)
}

Swift Biginteger xor encrypt/decrypt

Solved, below is the code.

Based on the great work at https://github.com/lorentey/BigInt

func encrypt(str:String, key:BigUInt)->String
{
let value = BigUInt(str.data(using: String.Encoding.utf8)!)
let encrypt = key ^ value
return String(encrypt, radix: 16)
}

func decrypt(str:String, key:BigUInt)->String
{
let value = BigUInt(str, radix: 16)!
let decrypt = key ^ value
return String(data: decrypt.serialize(), encoding: String.Encoding.utf8)!
}

Thanks again for everyone whoever contributed to the the BigInt library, that's why the code looks so simple.

How to decrypt simple XOR encryption

One of the cool things about XOR encryption is that when you apply it twice, you get back the original string – see http://en.wikipedia.org/wiki/XOR_cipher.

In your function, xor_decrypt, you take string and key and return string ^ key. If, now, you xor that with the key again, you get (string ^ key) ^ key = string ^ (key ^ key) = string ^ identity = string
(by properties of XOR operator: http://en.wikipedia.org/wiki/Exclusive_or#Properties)

Thus, you can just run your function, xor_encrypt, a second time on the output of the first xor_encrypt.

Swift - Encrypt and decrypt a string using a users password

Please see updated section below striked out section. I have left the striked out section to give context to the comments and to show how not to do for security purposes

I have worked it out using CryptoSwift

func testEnc() throws {

//has to be 16 characters
//ivKey is only hardcoded for use of this example
let ivKey = "tEi1H3E1aj26XNro"
let message = "Test Message"
let password = "pass123"

//key has to be 32 characters so we pad the password
let aesKey = password.padding(toLength: 32, withPad: "0", startingAt: 0)

let encrypted = try message.encryptToBase64(cipher: AES(key: aesKey, iv: ivKey, blockMode: .CBC, padding: .pkcs7))
//returns: beQ7u8hBGdFYqNP5z4gBGg==

let decrypted = try encrypted?.decryptBase64ToString(cipher: AES(key: aesKey, iv: ivKey, blockMode: .CBC, padding: .pkcs7))
//returns: Test Message
assert(message == decrypted)

}

UPDATE

The above methodology, while it will work, is insecure; please read comments on this answer for more information

Based on the comments and feedback, I have written a new example that uses the framework RNCryptor

To encryp and decrypt messages I use the following 2 methods.

    func encryptMessage(message: String, encryptionKey: String) throws -> String {
let messageData = message.data(using: .utf8)!
let cipherData = RNCryptor.encrypt(data: messageData, withPassword: encryptionKey)
return cipherData.base64EncodedString()
}

func decryptMessage(encryptedMessage: String, encryptionKey: String) throws -> String {

let encryptedData = Data.init(base64Encoded: encryptedMessage)!
let decryptedData = try RNCryptor.decrypt(data: encryptedData, withPassword: encryptionKey)
let decryptedString = String(data: decryptedData, encoding: .utf8)!

return decryptedString
}

In my use case I needed to be able to handle encryption and decryption based off a password that could be changed without having to re-encrypt everything.

What I did is generated a random 32 character string and encrypted that with the password. If the user changes their password, they simply decrypt the key with the old password and re-encrypt it with the new password. This ensure that all existing content can be decrypted while still being secured by the user's password.

To generate the encryption key is use the following method:

func generateEncryptionKey(withPassword password:String) throws -> String {
let randomData = RNCryptor.randomData(ofLength: 32)
let cipherData = RNCryptor.encrypt(data: randomData, withPassword: password)
return cipherData.base64EncodedString()
}

Note: You would only generate this encryption key for the user once as it would then be stored somewhere where the user can return it using their password.

UInt8 XOR'd array result to NSString conversion returns nil every time

To store an arbitrary chunk of binary data as as a string, you need
a string encoding which maps each single byte (0 ... 255) to some
character. UTF-8 does not have this property, as for example 160
is the start of a multi-byte UTF-8 sequence and not valid on its own.

The simplest encoding with this property is the ISO Latin 1 aka
ISO 8859-1, which is the
ISO/IEC 8859-1
encoding when supplemented with the C0 and C1 control codes.
It maps the Unicode code points U+0000 .. U+00FF
to the bytes 0x00 .. 0xFF (compare 8859-1.TXT).

This encoding is available for
(NS)String as NSISOLatin1StringEncoding.

Please note: The result of converting an arbitrary binary chunk to
a (NS)String with NSISOLatin1StringEncoding will contain embedded
NUL and control characters. Some functions behave unexpectedly
when used with such a string. For example, NSLog() terminates the
output at the first embedded NUL character. This conversion
is meant to solve OP's concrete problem (creating a QR-code which
is recognized by a 3rd party application). It is not meant as
a universal mechanism to convert arbitrary data to a string which may
be printed or presented in any way to the user.

SwiftUI / iOS / iPhone how to encrypt data/ image before storing and where / how to store locally, general best practice?

Yes you can just store it in the documents folder by using file manager:

FileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)[0]

As for encryption, if you encrypt the data before writing them to disk then they are encrypted...

One issue is that the encryption key has to be stored securely as well. For this, I usually generate the key when it is first used and store in keychain. Hard-coding the key in the code is not as secure because it makes the key identical for all users, and the binary can (not sure how easy) be reverse-engineered. We have to trust Apple's keychain to be secure. Some checks for jailbreaking may also help hear.

Also note that unlike other app data (UserDefaults, files etc), keychain is NOT cleared when the app is reinstalled!!! This can be a major source of headache. If desired, you can work around this by running a a chunk of code to clear the keychain when the app runs the first time after installation (by keeping a flag in UserDefaults, for example, which is cleared when app is reinstalled).

iOS: How to intercept and manipulate bytes in AVPlayer

You'll want to use MTAudioProcessingTap for this, which is a property of AVPlayer's AVAudioMix. In your tap process callback, use MTAudioProcessingTapGetSourceAudio to grab your buffers. Once you have your buffer reference you can xor the data.

There's some boilerplate needed to get the AVAudioMix and MTAudioProcessingTap setup properly. The sample code that Apple has is pretty old, but still should work.
https://developer.apple.com/library/archive/samplecode/AudioTapProcessor/Introduction/Intro.html#//apple_ref/doc/uid/DTS40012324

Also note that it will be easier to do this in Objective C, for several reasons. The interop with your C file will be easier, and it is much more straightforward reading/writing to the buffer in Objc. It will also run faster than in swift. If you are interested to seeing what this would look like in swift, there is a sample project here:
https://github.com/gchilds/MTAudioProcessingTap-in-Swift

decrypt/encrypt xor algorithm in C

At first, you need to understand question correctly. Your question states that key is embedded at start of your cipher and its length is keyLength. So you need to separate this part and xor it with the rest of cipher.

Code should be similar to this:

void print_cipher_message(unsigned char cipher[], int keyLength) {
for (int i = 0; i < strlen((char*)cipher) - keyLength; i++) {
cipher[i + keyLength] = cipher[i + keyLength] ^ cipher[i % keyLength];
}

printf("%s", cipher + keyLength);
}

I wrote it off top of head quickly without debugging, so it may have bugs. In addition, question is not correct itself. it needs length of cipher and we cannot really use strlen() for it.



Related Topics



Leave a reply



Submit