     ///
     public func encrypt(data: NSData) -> NSData? {
         if let publicKey = obtainKey(.Public) {
-            // Determine appropriate AES key size
+            let algorithm = CCAlgorithm(kCCAlgorithmAES128)
             let blockSize = SecKeyGetBlockSize(publicKey)
-            let keySize: Int
-            if blockSize >= 256 {
-                keySize = Int(kCCKeySizeAES256)
-            } else if blockSize >= 192 {
-                keySize = Int(kCCKeySizeAES192)
-            } else {
-                keySize = Int(kCCKeySizeAES128)
-            }
-            
-            if let aesKey = Heimdall.generateSymmetricKey(keySize), encrypted = Heimdall.encrypt(data, key: aesKey, algorithm: CCAlgorithm(kCCAlgorithmAES128)) {
+            let ivSize = Heimdall.blockSize(algorithm)
+            let keySize = Heimdall.keySize(blockSize - ivSize)
+            
+            if let aesKey = Heimdall.generateRandomBytes(keySize), iv = Heimdall.generateRandomBytes(ivSize),
+                encrypted = Heimdall.encrypt(data, key: aesKey, iv: iv, algorithm: algorithm) {
                 // Final resulting data
                 let result = NSMutableData()
                 
-                // Encrypt the AES key with our public key
-                var encryptedData = [UInt8](count: Int(blockSize), repeatedValue: 0)
+                // Encrypt the AES key and IV with our public key
                 var encryptedLength = blockSize
-                let data = UnsafePointer<UInt8>(aesKey.bytes)
-                
-                switch SecKeyEncrypt(publicKey, .PKCS1, data, Int(aesKey.length), &encryptedData, &encryptedLength) {
-                case noErr:
-                    result.appendBytes(&encryptedData, length: encryptedLength)
-                default:
+                var encryptedData = [UInt8](count: encryptedLength, repeatedValue: 0)
+                
+                let rawKeyIVData = NSMutableData(data: aesKey)
+                rawKeyIVData.appendData(iv)
+                
+                let keyIvBytes = UnsafePointer<UInt8>(rawKeyIVData.bytes)
+                
+                if SecKeyEncrypt(publicKey, .PKCS1, keyIvBytes, rawKeyIVData.length, &encryptedData, &encryptedLength) != noErr {
                     return nil
                 }
                 
+                // Order is simple, first block is metadata, then comes the message
+                result.appendBytes(&encryptedData, length: encryptedLength)
                 result.appendData(encrypted)
                 
                 return result

    ///
    public func decrypt(encryptedData: NSData) -> NSData? {
        if let key = obtainKey(.Private) {
            // First block size should be the encrypted AES key
            let blockSize = SecKeyGetBlockSize(key)
            let keyData = encryptedData.subdataWithRange(NSRange(location: 0, length: blockSize))
            let messageData = encryptedData.subdataWithRange(NSRange(location: blockSize, length: encryptedData.length - blockSize))
            
            // Decrypt the key
            if let decryptedKey = NSMutableData(length: blockSize) {
                let encryptedKeyData = UnsafePointer<UInt8>(keyData.bytes)
                let decryptedKeyData = UnsafeMutablePointer<UInt8>(decryptedKey.mutableBytes)
                var decryptedLength = blockSize
                
                let keyStatus = SecKeyDecrypt(key, .PKCS1, encryptedKeyData, keyData.length, decryptedKeyData, &decryptedLength)
                
                if keyStatus == noErr {
                    decryptedKey.length = Int(decryptedLength)
                    
                    // Decrypt the message
                    if let message = Heimdall.decrypt(messageData, key: decryptedKey, algorithm: CCAlgorithm(kCCAlgorithmAES128)) {
                        return message
                    }
                }

        }
    }
    
    private class func generateRandomBytes(count: Int) -> NSData? {
        var result = [UInt8](count: count, repeatedValue: 0)
        SecRandomCopyBytes(kSecRandomDefault, count, &result)
        
        return NSData(bytes: result, length: count)
    }
    
    private class func keySize(blockSize: Int) -> Int {
        if blockSize >= Int(kCCKeySizeAES256) {
            return kCCKeySizeAES256
        } else if blockSize >= Int(kCCKeySizeAES192) {
            return kCCKeySizeAES192
        } else {
            return kCCKeySizeAES128
        }
    }
    
    private class func blockSize(algorithm: CCAlgorithm) -> Int {
        switch Int(algorithm) {
        case kCCAlgorithmAES128, kCCAlgorithmAES:
            return kCCBlockSizeAES128
        case kCCAlgorithmDES:
            return kCCBlockSizeDES
        case kCCAlgorithm3DES:
            return kCCBlockSize3DES
        case kCCAlgorithmCAST:
            return kCCBlockSizeCAST
        case kCCAlgorithmRC2:
            return kCCBlockSizeRC2
        case kCCAlgorithmBlowfish:
            return kCCBlockSizeBlowfish
        default:
            return 0
        }
    }
    
    
    private class func encrypt(data: NSData, key: NSData, iv: NSData, algorithm: CCAlgorithm) -> NSData? {
        let dataBytes = UnsafePointer<UInt8>(data.bytes)
        let dataLength = data.length
        
        if let result = NSMutableData(length: dataLength + key.length + iv.length) {
            let keyData = UnsafePointer<UInt8>(key.bytes)
            let keyLength = size_t(key.length)
            let ivData = UnsafePointer<UInt8>(iv.bytes)
            
            let encryptedData = UnsafeMutablePointer<UInt8>(result.mutableBytes)
            let encryptedDataLength = size_t(result.length)
            
            var encryptedLength: size_t = 0
            
            let status = CCCrypt(CCOperation(kCCEncrypt), algorithm, CCOptions(kCCOptionPKCS7Padding), keyData, keyLength, ivData, dataBytes, dataLength, encryptedData, encryptedDataLength, &encryptedLength)
            
            if UInt32(status) == UInt32(kCCSuccess) {
                result.length = Int(encryptedLength)
