signalapp / libsignal

Home to the Signal Protocol as well as other cryptographic primitives which make Signal possible.
GNU Affero General Public License v3.0
3.08k stars 362 forks source link

[Swift] how can I use signal_aes256_gcm_decryption_new in ffi #477

Closed JuyeonYu closed 2 years ago

JuyeonYu commented 2 years ago

hello. I am struggling to use libSignal for Swift. after x3dh, now I get the key for encrypt and decrypt. So I am ready kdf message key, nonce, tag, and aead.

For encrypt and decrypt, we decided to use public static native void Aes256GcmDecryption_Update(long gcm, byte[] data, int offset, int length); public static native void Aes256GcmEncryption_Update(long gcm, byte[] data, int offset, int length); in java.

Q1. is signal_aes256_gcm_decryption_new in ffi function same as above java function?

SignalFfiError *signal_aes256_gcm_decryption_new(SignalAes256GcmDecryption **out, SignalBorrowedBuffer key, SignalBorrowedBuffer nonce, SignalBorrowedBuffer associated_data);

SignalFfiError signal_aes256_gcm_decryption_update(SignalAes256GcmDecryption gcm, SignalBorrowedMutableBuffer data, uint32_t offset, uint32_t length);

SignalFfiError signal_aes256_gcm_decryption_verify_tag(bool out, SignalAes256GcmDecryption *gcm, SignalBorrowedBuffer tag);

if so, could you give me a sample source how to use the function?

jrose-signal commented 2 years ago

These are general-purpose AES-256-GCM APIs that we haven't finished hooking up to Swift; though they should work as C functions, the C interface is considered an implementation detail and may change from release to release without notice. (But you probably already know that.) The signal_aes256_gcm_decryption_update C function is equivalent to the Java function you pasted (twice, presumably that was an accident). But…are you using this to implement the Signal protocol? LibSignal exposes higher-level operations for that.


That said, the usage from C would be something like

SignalFfiError *error;
SignalAes256GcmDecryption *decrypt;
error = signal_aes256_gcm_decryption_new(&decrypt, key, nonce, associatedDataFromWhenYouEncrypted);
if (error) { return NULL; }

error = signal_aes256_gcm_decryption_update(decrypt, message, 0, message.length); // modifies 'message'
if (error) { return NULL; }

bool valid = false;
error = signal_aes256_gcm_decryption_verify_tag(&valid, decrypt, tag); // VERY IMPORTANT
if (error || !valid) { return NULL; }

error = signal_aes256_gcm_decryption_destroy(decrypt);
if (error) { /* log, maybe? */ }

char *result = malloc(message.length);
memcpy(result, message.buffer, message.length);
return result;

I'll note that this is a relatively "unsafe" implementation of AES-GCM, because it requires you to remember to call verify_tag at the end. If the tag doesn't verify, the decrypted message must be thrown away. A more common API would have you decrypt-and-verify as a single operation to be safe, but that requires the whole message be in memory at once.

JuyeonYu commented 2 years ago

thank you for your reply! I couldn't fully understand what you said. :(

Q1. in Swift, is "Aes256GcmSiv class" the higher-level operations for that? so can I decrypt without tag verify in safe?

and from your sample code I made the below code in Swift. but I don't know how can I make "SignalAes256GcmDecryption *decrypt;"(from your sample) in Swift.

Q2. how can I make decrypt variable below code? and... is that right approach?

var messageKey: [UInt8] = messageKeyHex.data(using: .utf8)?.bytes
var tag: [UInt8] = tagHex.data(using: .utf8)?.bytes
var nonce: [UInt8] =  nonceHex.data(using: .utf8)?.bytes
var aead: [UInt8] = aeadHex.data(using: .utf8)?.bytes
var cypher: [UInt8] = cypherHex.data(using: .utf8)?.bytes

withUnsafePointer(to: messageKey[0]) { messageKeyPointer in
  withUnsafePointer(to: tag[0]) { tagPointer in
    withUnsafePointer(to: nonce[0]) { noncePointer in
      withUnsafePointer(to: aead[0]) { aeadPointer in
        withUnsafeMutablePointer(to: &myCypher[0]) { cypherPointer in
          let messageKeyBuffer = SignalBorrowedBuffer(base: messageKeyPointer, length: UInt(messageKey.count))
          let tagBuffer = SignalBorrowedBuffer(base: tagPointer, length: UInt(tag.count))
          let nonceBuffer = SignalBorrowedBuffer(base: noncePointer, length: UInt(nonce.count))
          let aeadBuffer = SignalBorrowedBuffer(base: aeadPointer, length: UInt(aead.count))
          let cypherBuffer = SignalBorrowedMutableBuffer(base: cypherPointer, length: UInt(cypher.count))

          // how to make the ??? arguement below?
          var error = signal_aes256_gcm_decryption_new(???, messageKeyBuffer, nonceBuffer, aeadBuffer)
          if error != nil { }

          // how to make the ??? arguement below?      
          error = signal_aes256_gcm_decryption_update(???, cypherBuffer, 0, UInt32(cypher.count))
          if error != nil { }

          // how to make the ??? arguement below?
          var valid: Bool = false
          error = signal_aes256_gcm_decryption_verify_tag(&valid, ???, tagBuffer)
          if error != nil { }
        }
      }
   }
}

}

thank you again for your reply!