Skip to content

sentryco/Cipher

Repository files navigation

Tests codebeat badge

Cipher πŸ”

A Swift Encryption Library Simplifying CryptoKit

Cipher is a Swift encryption library that acts as a simplified wrapper around Apple's CryptoKit. It streamlines cryptographic operations, making it easier for developers to implement robust encryption without delving into the complexities of cryptography. With Cipher, you can effortlessly generate key pairs, create shared keys for end-to-end encryption, and encrypt and decrypt data using password-derived keys.

Table of Contents

Why Cipher?

  • Simplicity: Cipher provides an easy-to-use API that abstracts away the complexities of cryptography.
  • Security: Built on top of CryptoKit, Cipher ensures your encryption follows industry best practices.
  • Comprehensive Features: From key generation to secure messaging, Cipher covers a wide range of cryptographic needs.

Key Features

  • πŸ”‘ Key Generation: Generate symmetric and asymmetric keys for encryption and decryption.
  • πŸ”’ Data Encryption and Decryption: Securely encrypt and decrypt data using symmetric keys.
  • πŸ”„ End-to-End Encryption: Utilize Diffie-Hellman key agreement to create shared keys for secure communication.
  • πŸ” Password-Based Encryption: Encrypt and decrypt data using a password-derived key.
  • πŸ“€ Key Export and Import: Easily export and import keys for storage or transmission.
  • πŸ€– User-Friendly API: Simplifies cryptographic operations with an intuitive interface.

Installation

To integrate Cipher into your Xcode project using Swift Package Manager, add the following to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/sentryco/Cipher.git", from: "1.0.0")
]

Alternatively, you can add it directly through Xcode:

  1. Go to File > Add Packages...
  2. Enter the repository URL: https://github.com/sentryco/Cipher.git
  3. Select the desired version and click Add Package.

Examples

Generating Keys

Generate a new key pair (private and public keys):

import Cipher

do {
    let keyPair = try Cipher.keyPair()
    let privateKey = keyPair.privateKey
    let publicKey = keyPair.publicKey
} catch {
    print("Failed to generate key pair: \(error)")
}

Creating a Shared Key for End-to-End Encryption

Create a shared symmetric key using your private key and the recipient's public key:

do {
    let sharedKey = try Cipher.sharedKey(privateKey: myPrivateKey, publicKey: recipientPublicKey)
} catch {
    print("Failed to create shared key: \(error)")
}

Encrypting and Decrypting Data with a Password

Encrypt and decrypt data using a password-derived key:

do {
    // Derive key from password
    let passwordKey = try Cipher.passwordKey(password: "your_secure_password")
    
    // Encrypt data
    let messageData = "Sensitive information".data(using: .utf8)!
    let encryptedData = try Cipher.encrypt(data: messageData, key: passwordKey)
    
    // Decrypt data
    let decryptedData = try Cipher.decrypt(data: encryptedData, key: passwordKey)
    let message = String(data: decryptedData, encoding: .utf8)
    
    print(message) // Outputs: Sensitive information
} catch {
    print("Encryption/Decryption error: \(error)")
}

Real-World Scenario: Secure Messaging

Implementing secure messaging between users:

// User A generates key pair
let userAKeyPair = try Cipher.keyPair()
let userAPrivateKey = userAKeyPair.privateKey
let userAPublicKey = userAKeyPair.publicKey

// User B generates key pair
let userBKeyPair = try Cipher.keyPair()
let userBPrivateKey = userBKeyPair.privateKey
let userBPublicKey = userBKeyPair.publicKey

// Exchange public keys between User A and User B

// User A creates shared key
let sharedKeyA = try Cipher.sharedKey(privateKey: userAPrivateKey, publicKey: userBPublicKey)

// User B creates shared key
let sharedKeyB = try Cipher.sharedKey(privateKey: userBPrivateKey, publicKey: userAPublicKey)

// User A encrypts a message
let originalMessage = "Hello, User B!".data(using: .utf8)!
let encryptedMessage = try Cipher.encrypt(data: originalMessage, key: sharedKeyA)

// User B decrypts the message
let decryptedMessageData = try Cipher.decrypt(data: encryptedMessage, key: sharedKeyB)
let decryptedMessage = String(data: decryptedMessageData, encoding: .utf8)
print(decryptedMessage) // Outputs: Hello, User B!

Exporting and Importing Keys

You can export and import keys to facilitate key migration or storage:

import Cipher

do {
    // Generate a key pair
    let keyPair = try Cipher.keyPair()
    let privateKey = keyPair.privateKey
    let publicKey = keyPair.publicKey

    // Export private key to a string
    let privateKeyString = try Cipher.exportPrivKey(privKey: privateKey)

    // Import private key from a string
    let importedPrivateKey = try Cipher.importPrivKey(privKey: privateKeyString)

    // Export public key to a string
    let publicKeyString = try Cipher.exportPubKey(pubKey: publicKey)

    // Import public key from a string
    let importedPublicKey = try Cipher.importPubKey(pubKey: publicKeyString)

    // Verify that the keys match
    assert(privateKey.rawRepresentation == importedPrivateKey.rawRepresentation)
    assert(publicKey.rawRepresentation == importedPublicKey.rawRepresentation)
} catch {
    print("Key migration error: \(error)")
}

Working with Salt

Salt is critical in cryptographic operations to prevent rainbow table attacks and ensure the uniqueness of derived keys.

import Cipher

// Generate a random salt of 128 bytes
let salt = Cipher.randomSalt(length: 128)

// Use the salt in key derivation or encryption operations
do {
    let sharedKey = try Cipher.sharedKey(privateKey: myPrivateKey, publicKey: recipientPublicKey, salt: salt)
} catch {
    print("Failed to create shared key: \(error)")
}

Best Practices:

  • Use a unique salt for each encryption operation.
  • Store or transmit the salt securely alongside the ciphertext.
  • Avoid using predictable or static values for the salt.

Note: Ensure the salt is stored or transmitted securely alongside the ciphertext for decryption.

Cryptographic Best Practices

Cipher follows cryptographic best practices to ensure data security:

  • Authenticated Encryption: Uses modes like ChaCha20-Poly1305 to provide confidentiality and integrity.
  • Secure Key Sizes: Employs appropriate key sizes (e.g., 256-bit symmetric keys).
  • Key Derivation Functions: Utilizes secure KDFs with appropriate salts and iteration counts.
  • Secure Randomness: Generates keys and salts using secure random number generation.

Resources

Topic Link
Diffie hellman Link
CryptoKit Link
xchacha20 Link
Encrypting data with CryptoKit and custom password Link
Common cryptographic operations in Swift with CryptoKit Link

Other Encryption Libraries

Library Link
Argon2id Link
Blake2b Link
XChaCha20 Link
Poly1305 Link
swift-sodium Link

Related encryption libs:

Todo:

  • Add more / better doc and examples βœ…
  • Show how migration API would work etc βœ…
  • Add some more doc around salt πŸ‘ˆ
  • Add Introduction: Expand the introduction to include more details about the library. What makes it unique? Why should someone use it over other libraries? What problems does it solve? Installation: Include a section on how to install and setup your library. This could include the commands to run, any dependencies that need to be installed, etc.
  • Add Usage: Expand the examples section to include more comprehensive examples. Show how to use the library in a real-world scenario. This could include examples of how to handle errors, how to use the library in a larger project, etc.
  • Provide an in-depth explanation of what salt is and its role in cryptography.
  • Discuss how Cipher handles salt and any methods available for salt generation.
  • Emphasize best practices and common pitfalls.

About

Encryption lib (CryptoKit wrapper)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages