Monday, 10 February 2020

XOR encryption and decryption with Swift

In most iOS apps we might have API key constants. Instead of keeping them as plain text, we can use XOR encrypted value and decrypt on app launch.

/// XOR encrypt plain text with a key.
/// - Parameters:
///     - plainText: A plain text for encryption.
///     - withKey: Encryption key.
/// - Returns: An array containing encrypted bytes
func xorEncrypt(_ plainText: String, withKey: String) -> [UInt8] {
    var encrypted: [UInt8] = []
    if plainText.isEmpty {
        return []
    }
    let text: [UInt8] = Array(plainText.utf8)
    let key: [UInt8] = Array(withKey.utf8)
    let len = key.count
    text.enumerated().forEach { idx, elem in
        encrypted.append(elem ^ key[idx % len])
    }
    return encrypted
}

/// XOR decrypt cipher text with a key.
/// - Parameters:
///     - cipherText: A cipher text for decryption.
///     - withKey: Decryption key.
/// - Returns: The decrypted string.
func xorDecrypt(_ cipherText: [UInt8], withKey: String) -> String {
    var decrypted: [UInt8] = []
    if cipherText.count == 0 {
        return ""
    }
    let key: [UInt8] = Array(withKey.utf8)
    let len = key.count
    cipherText.enumerated().forEach { idx, elem in
        decrypted.append(elem ^ key[idx % len])
    }
    return String(bytes: decrypted, encoding: .utf8)!
}

Using the above xorEncrypt function will give an array of numbers which we can add as a constant. On app launch, use the xorDecrypt function with the array value and the same key to get the plain text back.

Change the default prompt in Terminal

The latest version of macOS uses zsh as the shell. To change the prompt in the Terminal we can do the following.

1. Install oh-my-zsh which provides many enhancements to the zsh.
2. Install spaceship theme.
npm install -g spaceship-prompt
3. Set the theme to spaceship and the prompt symbol to λ from the default % by add the below in the .zshrc file
ZSH_THEME="spaceship"
SPACESHIP_CHAR_SYMBOL='λ '
# Set Spaceship ZSH as a prompt
autoload -U promptinit; promptinit
prompt spaceship
4. Source the configuration source ~/.zshrc or relaunch the terminal. We will have our updated prompt in the Terminal.

Thursday, 19 December 2019

DreamLisp - A Lisp dialect in Objective-C

DreamLisp is a Lisp dialect that started out as an implementation of MAL (Make a Lisp) and then diverged from the MAL language specification to include additional functionalities like modules, lazy collections and changes to some of the core functions, and is a Lisp-2 because we can have both variable and a function with the same name. DreamLisp is written in Objective-C and as such can be extended further to work with Objective-C runtime capabilities. See the experimental objc-rt-1 branch. At present, the language runs in interpreted mode.

The language takes inspiration from MAL which itself is heavily influenced by Clojure, LFE and Erlang. DreamLisp has unhygeinic macros, is single-threaded for the most part has bunch of built-in module core, network, test. Core module contains the native functions implemented in Objective-C and exposed to DreamLisp. The network module has function to make simple REST based HTTP requests. The test module contains macros and functions to write unit tests which resembles Clojure tests.

The main goal of the project was to have a working Lisp that can use all the Objective-C runtime capabilities and thereby develop software that runs on Apple devices using Lisp. In that front, we need a Lisp language, REPL and there is nothing better than having the language itself be written in Objective-C directly. This helps to use Objective-C internal functions without having to resort to FFIs. The language part is ready, i.e, the specification and the implementation. Even though it's Lisp, it's not Common Lisp or any other Lisp. It's a dialect of its own. Next is the Objective-C interop, which is partial. These built-in functions follow ideas from CLOS. Currently, we can dynamically create class, add methods, create objects of the class, invoke methods for a certain set use cases. We can also create objects of the built-in classes and invoke methods on it. It's not robust yet and interop between native Objective-C types and DLisp types are not fully functional, also the Lisp case to camel, Pascal casing and vice-versa. Once we have these, then we can use the same code to run through a transpiler written in DLisp, generate Objective-C or Swift code, then use xcodebuild to generate native code with no eval and the code will be just like handwritten code.

Currently, the language is fully interpreted and as such works for simple use cases, but with full-fledged app development, having a language that runs natively either using LLVM or atleast JIT would provide a better development experience. In that regards, I find malc interesting, which is MAL to LLVM or targetting MMIX bytecode. MMIX is a RISC architecture by Donald Knuth and is really cool.

Sunday, 15 December 2019

dnet - An LFE OTP REST API Server

I have created a seed project which uses LFE OTP with Cowboy for as the webserver and Mnesia as the database. There is also a gen_server which does HTTP request using Cowboy Gun library and handles the response as a stream asynchronously. This allows finer control over the HTTP response and allows to pause, cancel the stream, as well as continue from partially left of streams. The project demonstrates the use of LFE with OTP for writing web services with rebar3 for build and dependency management. Also, there are scripts for loading project env into LFE REPL, giving a full modern development workflow experience.

The supervision tree for the app is given below.


               ┌──────┐
          ┌───▶│db-sup│
          │    └──────┘
          │
┌────┐    │    ┌────────────┐
│dnet│────┼───▶│dnet-svc-sup│
└────┘    │    └────────────┘
          │
          │    ┌────────┐
          └───▶│http-sup│
               └────────┘

The server listens on port 8080 and has two handlers, one for GET and another for POST. The GET handler returns JSON and the POST handler returns HTML generated using Exemplar.

LFE comes with an emacs mode. So I have Spacemacs configuration setup with LFE mode with Lisp and general editor enhancements like rainbow-delimiters, OS X keybindings and such. The LFE mode files are currently configured to load from ~/env/emacs/lfe directory.

Saturday, 14 December 2019

NSJSONSerialization of BOOL values

To serialize BOOL values using NSJSONSerialization, we can use the NSNumber form. i.e, @YES and @NO which represents the BOOL YES and NO respectively.

Friday, 1 November 2019

Workaround for Performance Issue in Firestore get API

In the Firestore SDK for iOS, calling any get APIs like getDocument, getDocuments takes a long time. An empirical estimate is for a collection containing around 10,000 documents, it's taking around 20 seconds or more to retrieve the latest 50 documents. The workaround is to use addSnapshotListener once and remove after we obtain the data. This makes the retrieval fast enough.

Friday, 27 September 2019

Using Expressions in LLDB

Often times we would want to hold some temporary variables when debugging with lldb. We can make use of expression in such cases. An expression, short form e or expr evaluates the given statement. If we use an assignment with a variable starting with $, that variable will be available through out and can be used in other expressions.
(lldb) expr NSRange $range1 = NSMakeRange(0, 3);
(lldb) expr [@"Hi Olive" substringWithRange:(NSRange)$range1];
(NSTaggedPointerString *) $9 = 0x7a858d27bb2607ed @"Hi "
Since we are in single-line expression mode, there are slight differences in the way the expressions work. We need to cast NSRange. A better option in this case is to use the multi-line expression mode. For that, first enter expr↩ followed by a carriage return. The lldb is now in multi-line expression mode where we can enter normal Objective-C (or Swift) code with each line terminated with a semi-colon and an empty line after the final statement will evalute all the expressions and exit the mode.
(lldb) expr
Enter expressions, then terminate with an empty line to evaluate:
1 NSRange range = NSMakeRange(9, 4);
2 NSString *str = @"Slice of Life";
3 [str substringWithRange:range];
4 
(NSTaggedPointerString *) $4 = 0x7a858d42fd26039d @"Life"
(lldb)
Multi-line expression with lldb makes debugging much better.