Awesome
obfuscateapi
Mac OSX, Command line Swift 4 Utility for obfuscate (mostly API endpoints) in AES128 format.
Contents
Motivation
The list of endpoints or servers that an iOS app have, is restricted information that should not be disclosed, usually developers create that network services definition in a constants file or even worse, in a plist.
A plist is easily breakable and plain text strings are also (see strings command), so anyone with a minimum of knowledge can get to know how is our network services definition, who leaves it prone to attacks.
So doing like this, is a bad security practice:
struct APIConstants {
static let baseURL = "https://server.com"
static let deviceBinding = "api/devideBinding"
This command line utility creates two Swift 4 compatible files:
- An
APIConstants.swift
file. With strings from network layer encrypted in AES128 CBC format. See how it looks now:
struct APIConstants {
/// Base URL (https://pr2studio.com)
static let baseURL = "Cs6WqbJ4uVMXUhQ/pU96WF/wsWAT5yiBqfGVG99XZ0M="
/// Device binding (/means/getbinding)
static let deviceBinding = "Ja2p49mofIichhwVjkgQlIKQC/RDNBZe4PtZUCMaYCY="
- An inline method in file
AESKeyClass.swift
where password is scrambled. See it for password: secretpassword
import Foundation
// using key (ALongHiddenKey9)
@inline(__always) public func aesKey() -> [UInt8] {
return [
0x7C-0x09, 0x66-0x01, 0x51+0x12, 0x01+0x71, 0x0C+0x59, 0x59+0x1B,
0x44+0x2C, 0x6F-0x0E, 0xCA-0x57, 0x8D-0x1A,
0xAD-0x36, 0x56+0x19, 0xD9-0x67, 0x7E-0x1A
]
}
Technology
-
It uses AES128 CBC format, with an optional
iv
, if you don´t specify it, the defaultiv
will be00000000000000000000000000000000
-
Symmetric encryption
-
Uses standards. Done with Apple CommonCrypto and standard format. No third parties or propietary formats.
-
inline function for the aes key. So it will be more difficult to hijack it, and the attacker would need to patch all occurrences of it.
-
the inlined bytes are generated pseudo-ramdomly, so every time you run it, it will generate different hexs with operations
-
we can deploy a new version of the app with a new AES key. Just running again this command utility.
-
Secure enough
Install
1 Install Command Line Developer tools.
The easiest way is with: xcode-select --install
2 Adjust the ouput files to your needs
If you want to edit the output files format, this can be done changing how they will be created in main.swift
3 Archive the project
From your achived project, you will have an obfuscateapi date.xcarchive
file
4 Copy executable to your usr/local/bin folder
Go to xcarchive, show contents and locate Products/usr/local/bin/obfuscateapi
and copy it to your /usr/local/bin
folder
Running it
Open a command line in Terminal and run the command obfuscateapi
NAME
obfuscateapi - obfuscates a plist to classes in AES128 format
SYNOPSIS
obfuscateapi -key aeskey [-iv ivstring] [-infile file]
DESCRIPTION
The following options are available:
-key the key for encrypting. Better to use a long one
-iv initialization vector. By default is 00000000000000000000000000000000
-infile plist to convert to classes. bu default is apiplain.plist
It will generate two files APIConstants.swift
with the encrypted strings and AESKeyClass.swift
with a function to retrieve the key
infile plist format
We should describe the network services in a plist, this is a sample plist. Each entry has three parts (dictionary with a long name for comments, constant name and value. Sample with three constants:
<key>Base URL</key>
<dict>
<key>key</key>
<string>baseURL</string>
<key>value</key>
<string>https://pr2studio.com</string>
</dict>
<key>Device binding</key>
<dict>
<key>key</key>
<string>deviceBinding</string>
<key>value</key>
<string>/means/getbinding</string>
</dict>
<key>Send key</key>
<dict>
<key>key</key>
<string>sendKey</string>
<key>value</key>
<string>/means/sendkey</string>
</dict>
Using it
After generated the two files (APIConstants.swift
and AESKeyClass.swift
), you can copy it to your project, along with Crypto+Extensions.swift
Then when you want to retrieve the string for an endpoint, you should do this:
let arrKeyString = String(data: Data(bytes: aesKey()), encoding: .utf8)
let endpoint = APIConstants.deviceBinding.aesDecryptWithKey(arrKeyString)
then use endpoint constant for doing yout network request
You can check if the strings generated work fine with this openssl command (first save the string ending with a carriage return in file test.enc):
openssl enc -aes128 -k secretpassword -p -iv 00000000000000000000000000000000 -nosalt -base64 -d -in test.enc
Some recommendations
- This is just one small step for App security, you should enforce more measures like jailbreak detection and SSL Pining among others.
- You will never be safe, whatever you do, but is better to do something than nothing
- Security is a feeling, users needs to feel secure enough
Credits
Pablo Roca Rozas. PR2Studio.
License
obfuscateapi is released under the MIT license. See LICENSE for details.