nuntius 0.0.9

nuntius 0.0.9

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最新发布2017年9月

Ivan Rodriguez维护。



nuntius 0.0.9

[β] nuntius

nuntius 是一个 iOS 框架,它帮助 iOS 开发者通过简单的 API 将端到端加密 (e2ee) 集成到他们的应用程序中。它提供 Extended Triple Diffie-Hellman (X3DH) 和 Double Ratchet 协议的 objc 实现,大多数加密操作使用 libsodium。nuntius 通过 AES-CBC-HMAC-256 提供 Authenticated Encryption with Associated Data (AEAD),它使用 Apple 的 CommonCrypto 框架进行这些操作,但在未来我将迁移到仅使用 libsodium 的加密并使用 ChaCha20-Poly1305

扩展三重 Diffie-Hellman (X3DH)

此处所述,X3DH 是一种密钥约定协议,它通过公开密钥互认来建立两个参与者之间的共享 会话 密钥。nuntius 使用

双摇螺钉

此处所述,在两个参与方(例如使用 X3DH)之间建立共享的 会话 密钥后,使用双摇螺钉协议来发送和接收加密消息。它在每次双摇螺钉消息后派生新的加密密钥提供 向前保密性 (FS),这意味着如果加密密钥被泄露,则不能用于解密旧消息。它提供了一个对称加密密钥 ratachet 和一个 Diffie-Hellman 公开密钥加密 ratachet,这就是为什么称为双摇螺钉。nuntius 使用

导入

使用

生成 Curve25519 密钥对

Objc

IREncryptionService *IREncryptionService = [IREncryptionService new];
IRCurve25519KeyPair *keyPair = [IREncryptionService generateKeyPair];
NSLog(@"Public Key: %@", keyPair.publicKey);
NSLog(@"Private Key: %@", keyPair.privateKey);

Swift

let IREncryptionService = IREncryptionService()
let keyPair = IREncryptionService.generateKeyPair()!
print("Public Key: \(keyPair.publicKey)")
print("Private Key: \(keyPair.privateKey)")

签名 Curve25519 公开密钥

Objc

IREncryptionService *IREncryptionService = [IREncryptionService new];
IRCurve25519KeyPair *signingKeyPair = [IREncryptionService generateKeyPair];
IRCurve25519KeyPair *signedKeyPair = [IREncryptionService generateKeyPair];
NSData *signature = [IREncryptionService signData:signedKeyPair.publicKey withKeyPair:signingKeyPair];
[signedKeyPair addKeyPairSignature:signature];
NSLog(@"Signature: %@", signedKeyPair.signature);

Swift

let IREncryptionService = IREncryptionService()
let signingKeyPair = IREncryptionService.generateKeyPair()!
let signedKeyPair = IREncryptionService.generateKeyPair()!
guard let signature = IREncryptionService.sign(signedKeyPair.publicKey, with: signingKeyPair) else {
    return
}
signedKeyPair.addSignature(signature)
print("Signature: \(signedKeyPair.signature!)")

验证 Curve25519 签名

Objc

IREncryptionService *IREncryptionService = [IREncryptionService new];
IRCurve25519KeyPair *signingKeyPair = //get signing key pair
IRCurve25519KeyPair *signedKeyPair = //get signed key pair
BOOL valid = [IREncryptionService verifySignature:signedKeyPair.signature ofRawData:signedKeyPair.publicKey withKeyPair:signingKeyPair];
if (valid) {
    NSLog(@"Valid signature");
} else {
    NSLog(@"Invalid signature");
}

Swift

let IREncryptionService = IREncryptionService()
let signingKeyPair = //get signing key pair
let signedKeyPair = //get signed key pair
let valid = IREncryptionService.verifySignature(signedKeyPair.signature!, ofRawData: signedKeyPair.publicKey, with: signingKeyPair)
if valid {
    print("Valid signature")
} else {
    print("Invalid signature")
}

从 2 个 Curve25519 密钥(ECDH)生成共享密钥

Objc

IREncryptionService *IREncryptionService = [IREncryptionService new];
//Alice is the sender
IRCurve25519KeyPair *aliceKeyPair = [IREncryptionService generateKeyPair];
//Bob is the receiver
IRCurve25519KeyPair *bobKeyPair = [IREncryptionService generateKeyPair];
NSData *sharedSecretAlice = [IREncryptionService senderSharedKeyWithRecieverPublicKey:bobKeyPair.publicKey andSenderKeyPair:aliceKeyPair];
NSData *sharedSecretBob = [IREncryptionService receiverSharedKeyWithSenderPublicKey:aliceKeyPair.publicKey andReceiverKeyPair:bobKeyPair];
if ([sharedSecretAlice isEqualToData:sharedSecretBob]) {
    NSLog(@"Success!");
} else {
    NSLog(@"Error!");
}

Swift

let IREncryptionService = IREncryptionService()
//Alice is the sender
let aliceKeyPair = IREncryptionService.generateKeyPair()!
//Bob is the receiver
let bobKeyPair = IREncryptionService.generateKeyPair()!
let sharedSecretAlice = IREncryptionService.senderSharedKey(withRecieverPublicKey: bobKeyPair.publicKey, andSenderKeyPair: aliceKeyPair)
let sharedSecretBob = IREncryptionService.receiverSharedKey(withSenderPublicKey: aliceKeyPair.publicKey, andReceiverKeyPair: bobKeyPair)
guard sharedSecretAlice != nil, sharedSecretBob != nil, sharedSecretAlice == sharedSecretBob else {
    return
}
print("Success!")

派生密钥

Objc

IREncryptionService *IREncryptionService = [IREncryptionService new];
NSData *sharedSecret = //some shared secret, for example ECDH(alice.privateKey,bob.publicKey)
/* MIN outputLength: 16, MAX outputLength: 64, Salt: key id */
NSData *key1 = [IREncryptionService sharedKeyKDFWithSecret:sharedSecret andSalt:1 outputLength:32];
NSData *key2 = [IREncryptionService sharedKeyKDFWithSecret:sharedSecret andSalt:2 outputLength:64];
NSLog(@"Derived Key1: %@", key1);
NSLog(@"Derived Key2: %@", key2);

Swift

let IREncryptionService = IREncryptionService()
let sharedSecret = //some shared secret, for example ECDH(alice.privateKey,bob.publicKey)
/* MIN outputLength: 16, MAX outputLength: 64, Salt: key id */
let key1 = IREncryptionService.sharedKeyKDF(withSecret: sharedSecret, andSalt: 1, outputLength: 32)
let key2 = IREncryptionService.sharedKeyKDF(withSecret: sharedSecret, andSalt: 2, outputLength: 64)
print("Key 1 \(key1!)")
print("Key 2 \(key2!)")

还有

- (NSData * _Nullable)rootKeyKDFWithSecret:(NSData * _Nonnull)secret
                                   andSalt:(uint64_t)salt
                              outputLength:(NSUInteger)outputLength;
- (NSData * _Nullable)chainKeyKDFWithSecret:(NSData * _Nonnull)secret
                                    andSalt:(uint64_t)salt
                               outputLength:(NSUInteger)outputLength;
- (NSData * _Nullable)messageKeyKDFWithSecret:(NSData * _Nonnull)secret
                                      andSalt:(uint64_t)salt
                                 outputLength:(NSUInteger)outputLength;

所有这些方法都可以用于派生密钥,它们是 Double Ratchet 协议的便捷方法。内部它们都使用相同的方法,但使用不同的 ctx(libsodium 的 crypto_kdf_derive_from_key 参数之一)

加密和解密

Objc

IREncryptionService *IREncryptionService = [IREncryptionService new];
NSData *data = [@"my-secret-data" dataUsingEncoding:NSUTF8StringEncoding];
NSData *aesKey = //Random AES key, for example key = KDF(sharedSecret, 1, 32)
NSData *hmacKey = //Random HMAC key, for example key = KDF(sharedSecret, 2, 32)
NSData *iv = //Random IV, for example key = KDF(sharedSecret, 3, 16)
NSMutableData *ratchetData = [NSMutableData new];
//Add Sender Ratchet Public Key
[ratchetData appendData:senderKeyPair.publicKey];
//Add Number of Sent Messages
const char numberOfSentMessages[1] = {0x0};
[ratchetData appendBytes:numberOfSentMessages length:sizeof(numberOfSentMessages)];
//Add Number of Sent Messages in Previous Chain
const char numberOfSentMessagesInPreviousChain[1] = {0x0};
[ratchetData appendBytes:numberOfSentMessagesInPreviousChain length:sizeof(numberOfSentMessagesInPreviousChain)];
NSError *error = nil;
NSData *ciphertext = [IREncryptionService aeEncryptData:data: symmetricKey:aesKey hmacKey:hmacKey iv:iv ratchetHeader:ratchetData error:&error];
if (error == nil) {
    NSLog(@"Encrypted data: %@", ciphertext);
    //Decrypting
    NSError *decryptionError = nil;
    NSData *plaintext = [IREncryptionService aeDecryptData:ciphertext symmetricKey:aesKey hmacKey:hmacKey iv:iv error:&decryptionError];
    if (decryptionError == nil) {
        NSLog(@"Plaintext: %@",plaintext);
    } else {
        NSLog(@"Error: %@", decryptionError);
    }
    
} else {
    NSLog(@"Error: %@", error);
}

Swift

let IREncryptionService = IREncryptionService()
let data = "my-secret-data".data(using: .utf8)!
let aesKey = //Random AES key, for example key = KDF(sharedSecret, 1, 32)
let hmacKey = //Random HMAC key, for example key = KDF(sharedSecret, 2, 32)
let iv = //Random IV, for example key = KDF(sharedSecret, 3, 16)
var ratchetData = Data()
//Add Sender Ratchet Public Key
ratchetData.append(aliceKeyPair.publicKey)
//Add Number of Sent Messages
let numberOfSentMessages: Int32 = 0x0
var beNumberOfSentMessages = numberOfSentMessages.bigEndian
ratchetData.append(UnsafeBufferPointer(start: &beNumberOfSentMessages, count: 1))
//Add Number of Sent Messages in Previous Chain
let numberOfSentMessagesInPreviousChain: Int32 = 0x0
var beNumberOfSentMessagesInPreviousChain = numberOfSentMessagesInPreviousChain.bigEndian
ratchetData.append(UnsafeBufferPointer(start: &beNumberOfSentMessagesInPreviousChain, count: 1))
do {
    let ciphertext = try IREncryptionService.aeEncryptData(data, symmetricKey: aesKey, hmacKey: hmacKey, iv: iv, ratchetHeader: ratchetData)
    print("Encrypted data: \(ciphertext)")
    //Decrypting
    let plaintext = try IREncryptionService.aeDecryptData(ciphertext, symmetricKey: aesKey, hmacKey: hmacKey, iv: iv)
    print("Plaintext: \(plaintext)")
} catch {
    print("Error \(error)")
}

您可以在 这里了解更多关于 双摇杆头部 是什么以及为什么需要它。对于在 Double Ratchet 协议之外加密/解密数据,还有

- (NSData * _Nullable)aeEncryptSimpleData:(NSData * _Nonnull)plaintextData
                             symmetricKey:(NSData * _Nonnull)symmetricKey
                                  hmacKey:(NSData * _Nonnull)hmacKey
                                       iv:(NSData * _Nonnull)iv
                                    error:(NSError * _Nullable * _Nullable)error;

- (NSData * _Nullable)aeDecryptSimpleData:(NSData * _Nonnull)cipherData
                             symmetricKey:(NSData * _Nonnull)symmetricKey
                                  hmacKey:(NSData * _Nonnull)hmacKey
                                       iv:(NSData * _Nonnull)iv
                                    error:(NSError * _Nullable * _Nullable)error;

双摇杆:设置、发送和接收消息

Objc

//Alice is the sender and Bob is the receiver
IRDoubleRatchetService *aliceDoubleRatchet = [IRDoubleRatchetService new];
NSData *aliceSharedSecret = //some shared secret, for example ECDH(alice.privateKey,bob.publicKey)
[aliceDoubleRatchet setupRatchetForSendingWithSharedKey:aliceSharedSecret andDHReceiverKey:bobKeyPair];

IRDoubleRatchetService *bobDoubleRatchet = [IRDoubleRatchetService new];
NSData *bobSharedSecret = //some shared secret, for example ECDH(bob.privateKey,alice.publicKey)
[bobDoubleRatchet setupRatchetForReceivingWithSharedKey:bobSharedSecret andDHSenderKey:alice.signedPreKeyPair];

//Sending messages
NSData *message = //some message
NSError *error = nil;
NSData *ciphertext = [aliceDoubleRatchet encryptData:message error:&error];
if (error == nil) {
    NSLog(@"Ready to send message: %@", ciphertext);
} else {
    NSLog(@"Error %@",error);
}

//Receiving message
NSData *plaintext = [bobDoubleRatchet decryptData:ciphertext error:&error];
if (error == nil) {
    NSLog(@"Message received: %@", plaintext);
} else {
    NSLog(@"Error %@",error);
}

Swift

//Alice is the sender and Bob is the receiver
let aliceDoubleRatchet = IRDoubleRatchetService()
let aliceSharedSecret = //some shared secret, for example ECDH(alice.privateKey,bob.publicKey)
aliceDoubleRatchet.setupRatchetForSending(withSharedKey: aliceSharedSecret, andDHReceiverKey: bobKeyPair)

let bobDoubleRatchet = IRDoubleRatchetService()
let bobSharedSecret = //some shared secret, for example ECDH(bob.privateKey,alice.publicKey)
bobDoubleRatchet.setupRatchetForReceiving(withSharedKey: bobSharedSecret, andDHSenderKey: alice.signedPreKeyPair)

//Sending messages
let message = //some message
do {
    let ciphertext = try aliceDoubleRatchet.encryptData(message)
    print("Ready to send message: \(ciphertext)")

    //Receiving message
    let plaintext = try bobDoubleRatchet.decryptData(ciphertext)
    print("Message received \(plaintext)")
} catch {
    print("Error \(error)")
}

双摇杆:从存储状态设置

Objc

NSDictionary<NSString *, NSString *> *state = [someDoubleRatchet doubleRatchetState];
//store state in local encrypted db

IRDoubleRatchetService *doubleRatchet = [IRDoubleRatchetService new];
NSDictionary<NSString *, NSString *> *state = //get double ratchet state from local encrypted DB
[doubleRatchet setupWithRatchetState:state];

Swift

let state = someDoubleRatchet.doubleRatchetState()
//store state in local encrypted db

let doubleRatchet = IRDoubleRatchetService()
let state = //get double ratchet state from local encrypted DB
doubleRatchet.setup(withRatchetState: state)

三方迪菲-赫尔曼:设置、共享密钥生成

Objc

IRCurve25519KeyPair *identityKeyPair = //generate IRCurve25519KeyPair
IRCurve25519KeyPair *signedPreKeyPair = //generate IRCurve25519KeyPair
NSArray<IRCurve25519KeyPair *> *ephemeralKeyPairs = //generate "X" IRCurve25519KeyPairs
IRTripleDHService *tripleDH = [[IRTripleDHService alloc] initWithIdentityKeyPair:identityKeyPair signedPreKeyPair:signedPreKeyPair ephemeralKeys:ephemeralKeyPairs];

//When sending a message
IRCurve25519KeyPair *rIdentityKey = //get receiver's identity key from server or db
IRCurve25519KeyPair *rSignedPreKey = //get receiver's signed pre-key from server or db
IRCurve25519KeyPair *rEphemeralKey = //get one of the receiver's ephemeral keys from server
NSData *sharedKey = [tripleDH sharedKeyFromReceiverIdentityKey:rIdentityKey receiverSignedPreKey:rSignedPreKey receiverEphemeralKey:rEphemeralKey];
//Use sharedKey

//When receiving a message
IRCurve25519KeyPair *sIdentityKey = //get sender's identity key from server or db
IRCurve25519KeyPair *sEphemeralKey = //get sender's signed pre-key from server or db
NSString *rEphemeralKeyID = //get ephemeral key id from received message's heeader
NSData *sharedKey = [tripleDH sharedKeyFromSenderIdentityKey:sIdentityKey senderEphemeralKey:sEphemeralKey receiverEphemeralKeyID:rEphemeralKeyID];
//Use sharedKey

Swift

let identityKeyPair = //generate IRCurve25519KeyPair
let signedPreKeyPair = //generate IRCurve25519KeyPair
let ephemeralKeyPairs: Array<IRCurve25519KeyPair> = //generate "X" IRCurve25519KeyPairs
let tripleDH = IRTripleDHService(identityKeyPair: identityKeyPair, signedPreKeyPair: signedPreKeyPair, ephemeralKeys: ephemeralKeyPairs)

//When sending a message
let rIdentityKey = //get receiver's identity key from server or db
let rSignedPreKey = //get receiver's signed pre-key from server or db
let rEphemeralKey = //get one of the receiver's ephemeral keys from server
let sharedKey = tripleDH.sharedKey(fromReceiverIdentityKey: rIdentityKey, receiverSignedPreKey: rSignedPreKey, receiverEphemeralKey: rEphemeralKey)
//Use sharedKey

//When receiving a message
let sIdentityKey = //get sender's identity key from server or db
let sEphemeralKey = //get sender's signed pre-key from server or db
let rEphemeralKeyID: String = //get ephemeral key id from received message's heeader
let sharedKey = tripleDH.sharedKey(fromSenderIdentityKey: sIdentityKey, senderEphemeralKey: sEphemeralKey, receiverEphemeralKeyID: rEphemeralKeyID)
//Use sharedKey

贡献

你想贡献吗?太棒了!我很乐意看到在这里开放一些 PR。

待办事项

  • [X] 添加示例/用法
  • [] 添加文档
  • [] 创建维基
  • [X] 将项目添加到 Travis CI

免责声明

  • 扩展的三方迪菲-赫尔曼和双摇杆协议的实现是从零开始开发的,与现有库没有共享任何源代码。
  • 此库与 X3DH 和双摇杆协议的作者无关,也没有得到他们的支持。