README.md

# CryptoCompatibility
 
2.0
 
CryptoCompatibility shows how to do common cryptographic operations using Apple APIs such that the results match other well-known cryptographic toolkits, most notably OpenSSL.
 
 
## Requirements
 
### Build
 
Xcode 8.0
 
The sample was built using Xcode 8.0 on OS X 10.11.6 with the macOS 10.12 SDK.  To build the sample open the project, make sure the `Tool` scheme is selected, and choose *Product* > *Build*.
 
The sample also includes unit tests for macOS and iOS.  The `Tool` scheme does not build these.  For instructions on how to build and run these tests, see the *macOS Unit Tests* and *iOS Unit Tests* sections, below.
 
### Runtime
 
OS X 10.9
 
Although the sample requires OS X 10.9, the core techniques it shows are compatible with older releases of macOS (back to 10.7) and also with iOS.   For more information about compatibility, see the *Compatibility* section, below.
 
 
## Packing List
 
The sample contains the following items:
 
* `README.md` — This file.
 
* `LICENSE.txt` — The standard sample code license.
 
* `CryptoCompatibility.xcodeproj` — An Xcode project for the sample.
 
* `Operations` — A directory containing numerous NSOperation subclasses that implement various cryptographic operations.  See *Supported Cryptographic Operations*, below, for details.
 
* `Tool` — A directory containing the source for the macOS test tool.
 
* `UnitTest` — A directory containing unit tests for the above-mentioned operations.
 
* `TestData` — A directory containing data to support the unit tests.
 
 
## Using the Sample
 
### Tool
 
If you run the tool with no parameters it will print a list of supported subcommands.
 
    $ ./CryptoCompatibility
    usage: CryptoCompatibility [-v] subcommand
 
    Subcommands:
 
    base64-encode [-l] file
 
To run a subcommand, pass it as an argument to the tool.
 
    $ ./CryptoCompatibility base64-encode -l /System/Library/Kernels/kernel
    z/rt/gcAAAEDAAAAAgAAABMAAABYEAAAAQAgAAAAAAAZAAAAOAEAAF9fVEVYVAAA
    AAAAAAAAAAAAACAAgP///wAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAcAAAAFAAAA
 
### macOS Unit Tests
 
To run the macOS unit tests, switch to the *UnitTest* scheme and select *Product* > *Test*.
 
**Note** When running the unit tests you may see various “Assertion failure” messages in Xcode’s console.  These aren’t a problem unless they cause the test to fail.  See the *Other Notes* section (below) for more details on this.
 
### iOS Unit Tests
 
To run the iOS unit tests, switch to the *UnitTest* scheme, select an appropriate simulator, and then choose *Product* > *Test*.
 
**Note** Both the macOS and iOS unit tests are **library tests**, that is, the *Host Application* popup in the *General* tab of the target editor is set to *None* (Xcode sometimes calls these *logic tests*).  Due to Xcode restrictions, iOS library tests can only run on the simulator; you can’t run them on a real device.  This shouldn’t be a problem because, for cryptographic work like this, the simulator is very accurate.
 
 
### OpenSSL Tests
 
You can test the `CryptoCompatibility` command line tool against the [OpenSSL command line tool][man1openssl] to verify that they both produce the same results.  To do this:
 
1. Build the project, as described in the *Build* section above.
 
2. Open a new Terminal window.
 
3. Change into the `CryptoCompatibility` directory.
 
4. Run the `ATestAgainstOpenSSL.py` script.
 
        $ UnitTest/ATestAgainstOpenSSL.py 
        Success
 
[man1openssl]: <https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/openssl.1.html>
 
### Java and PHP Tests
 
The sample includes trivial Java and PHP programs that demonstrate how to use those environments to create results that are compatible with its operations.  See the comments at the top of `UnitTest/ATestAgainstJava.java` and `UnitTest/ATestAgainstPHP.php` for more details.
 
 
## Supported Cryptographic Operations
 
The sample demonstrates the following cryptographic operations:
 
* Base64 encode (QCCBase64Encode) and decode (QCCBase64Decode)
 
* SHA1 and SHA2 digests (QCCSHADigest)
 
* HMAC-SHA message authentication code generation (QCCHMACSHAAuthentication)
 
* PBKDF2-SHA key derivation (QCCPBKDF2SHAKeyDerivation)
 
* AES-128/192/256 encryption and decryption, both ECB and CBC mode, both with padding (QCCAESPadCryptor) and without (QCCAESCryptor)
 
* AES-128/192/256 encryption and decryption, with support for large data sets, both ECB and CBC mode, with padding (QCCAESPadBigCryptor)
 
* RSA SHA sign (QCCRSASHASign, QCCRSASHASignCompat) and verify (QCCRSASHAVerify, QCCRSASHAVerifyCompat)
 
* low-level RSA encryption and decryption (QCCRSASmallCryptor, QCCRSASmallCryptorCompat), with PKCS#1 padding or OAEP padding
 
In all cases the results match those the results generated by OpenSSL (as present on OS X 10.11.6), except for PBKDF2-SHA where the results were tested against PHP 7.0.5.
 
 
## Design Notes
 
The various cryptographic operations (the NSOperation subclasses in the `Operations` directory) are intended to be very modular.  Each one is completely independent of all the other code in this sample.  To use an operation’s code in your project you can either:
 
* take the operation as a whole and add it to your project
 
* extract the code from the operation’s `-main` method and integrate it into your code
 
**Note** The cost of this independence is that there’s some redundancy between the various operations. For example, each operation that uses SHA defines its own enumeration for the various flavours of SHA.
 
To keep things simple the cryptographic operations were designed to work with relatively small amounts of data, such that the data easily fits in memory.  It would be quite easy to enhance any given operation to support larger amounts of data (by reading a file, say) but I did not do this here because I wanted to keep the code as simple as possible.
 
To get an example of how much work it is to support large data sets, compare QCCAESPadCryptor (which is a one-shot, in-memory operation) and QCCAESPadBigCryptor (which is a chunk-wise operation that can work with an arbitrarily large data set).
 
The RSA encryption and decryption operations (QCCRSASmallCryptor and QCCRSASmallCryptorCompat) are restricted to *very* small amounts of data.  The comments at the top of each operation’s header file explain why this is the case.
 
 
## Compatibility
 
All of the sample’s cryptographic operations work on both macOS and iOS.  The RSA operations include a normal (QCCRSASHASign, QCCRSASHAVerify, QCCRSASmallCryptor) and a *Compat* flavour (QCCRSASHASignCompat, QCCRSASHAVerifyCompat, QCCRSASmallCryptorCompat).  The normal operations require the unified crypto API introduced in macOS 10.12 and iOS 10, while the *Compat* operations work on older OS releases.  To make this work they have to include *three* different implementations of the core operation:
 
* *Unified*, based on the unified crypto API introduced in macOS 10.12 and iOS 10
 
* *Transforms*, based on the SecTransforms API on OS X 10.7 through 10.11.x
 
* *Raw*, based on uses the SecKeyRaw API on iOS 9 and earlier
 
One potential gotcha here is that running the *Compat* operations on a modern OS will never exercise the compatibility code path.  To help flush out problems on that path, each of the operations has a flag to force it to use the compatibilty code (`debugUseCompatibilityCode`).  That flag can be enabled for each test in RSAOperationsTestsCompat via the `sUseCompatibilityCode` flag.
 
The official deployment target for this sample is OS X 10.9 and iOS 8; it has been tested on those releases.  The core code should run on even older OS releases but be aware of the following gotchas:
 
* If you run the unit tests on OS X 10.7 or iOS 5, you’ll find that the *NoSalt* and *Degenerate* cases within `-testPBKDF2` fail.  This is because the implementation of `CCKeyDerivationPBKDF` on those systems does not work correctly with an empty salt.  This shouldn’t be a problem in practice because you should always use salt; not doing so significantly undermines the security of PBKDF2.
 
* The `-testRSASignError` unit test fails on OS X 10.7.x because, on that platform, the underlying security transform does not error when you ask it to sign a block of data with a public key (a oversight that was corrected on 10.8).  This shouldn’t be a problem in practice because signing with a public key is a programming error.
 
 
## Other Notes
 
When running the unit tests you may see various “Assertion failure” messages in Xcode’s console.  These aren’t a problem unless they cause the test to fail.  These messages occur because the unit tests exercise common erroneous code paths.  For example, this message:
 
    2016-08-23 17:39:32.486 xctest[79488:13142330] *** Assertion failure in -[QCCBase64Encode initWithInputData:], /Users/quinn/Desktop/CryptoCompatibility/Operations/QCCBase64Encode.m:26
 
is printed because the following `NSParameterAssert` (in `-[QCCBase64Encode initWithInputData:]`) fires:
 
    - (instancetype)initWithInputData:(NSData *)inputData {
        NSParameterAssert(inputData != nil);
    }
 
and that fires because it’s being specifically tested by the code in Base64OperationsTests:
 
    - (void)testBase64Throws {
        XCTAssertThrows((void) [[QCCBase64Encode alloc] initWithInputData:nil]);
    }
 
 
## Removed Operations
 
Version 1.0 of this sample included a QCCMD5Digest operation that calculated MD5 digests.  This has been removed because MD5 is no longer appropriate for cryptographic use.  If you need to calculate MD5 for other reasons, a non-cryptographic checksum perhaps, you can follow the approach shown by QCCSHADigest, calling `CC_MD5` instead of `CC_SHAxxx`.
 
Version 1.0 of this sample included a padding option of ‘none’ for its RSA cryptor operations.  This has been removed because it’s very hard to use safely (RSA without padding is deeply insecure).
 
 
## Feedback
 
If you find any problems with this sample, or you’d like to suggest improvements, please [file a bug][bug] against it.
 
[bug]: <http://developer.apple.com/bugreporter/>
 
 
## Version History
 
1.0 (Aug 2013) was the first shipping version.
 
2.0 (Sep 2016) was a significant update to support the new unified crypto APIs added in macOS 10.12 and iOS 10.  It removed support for MD5 digests and RSA without padding; see the “Removed Operations” section for details.  It added support for SHA2 (as a digest and in other places, like PBKDF2, where a digest is used implicitly).  It also added support for OAEP padding in the RSA cryptor.  Finally, there was the usual update to use the latest tools and techniques.
 
Share and Enjoy
 
Apple Developer Technical Support  
Core OS/Hardware
 
15 Sep 2016
 
Copyright (C) 2016 Apple Inc. All rights reserved.