firstfloorsoftware / flutter_sodium

Flutter bindings for libsodium
BSD 3-Clause "New" or "Revised" License
102 stars 47 forks source link

crypto_secretstream_xchacha20poly1305_pull failed with -1 #43

Closed vishnukvmd closed 3 years ago

vishnukvmd commented 3 years ago

Hey @kozw, firstly thank you so much for the great work.

I'm running into issues while trying to decrypt a large file that was encrypted with Xchacha20poly1305.

This is how I'm encrypting the file:

final key = Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
final chunkSize = 4 * 1024 * 1024; // 4 MB
final initPushResult = Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);

var bytesRead = 0;
var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;

while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
  var bufferLength = chunkSize;
  if (bytesRead + bufferLength >= inputFileLength) { // Last block
    bufferLength = inputFileLength - bytesRead;
    tag = Sodium.cryptoSecretstreamXchacha20poly1305TagFinal;
  }
  final buffer = await inputFile.read(bufferLength);
  bytesRead += bufferLength;
  final encryptedData = Sodium.cryptoSecretstreamXchacha20poly1305Push(
      initPushResult.state, buffer, null, tag);
  outputFile.writeFromSync(encryptedData);
}

This is how I'm decrypting the file:

final chunkSize = (4 * 1024 * 1024) + Sodium.cryptoSecretstreamXchacha20poly1305Abytes;
final pullState = Sodium.cryptoSecretstreamXchacha20poly1305InitPull(
    initPushResult.header, key);

var bytesRead = 0;
var tag = Sodium.cryptoSecretstreamXchacha20poly1305TagMessage;

while (tag != Sodium.cryptoSecretstreamXchacha20poly1305TagFinal) {
  var bufferLength = chunkSize;
  if (bytesRead + bufferLength >= inputFileLength) { // Last block
    bufferLength = inputFileLength - bytesRead;
  }
  final buffer = await inputFile.read(bufferLength);
  bytesRead += bufferLength;
  final pullResult = Sodium.cryptoSecretstreamXchacha20poly1305Pull(
      pullState, buffer, null);
  outputFile.writeFromSync(pullResult.m);
  tag = pullResult.tag;
}

Here the decryption "pull" fails with the following error:

crypto_secretstream_xchacha20poly1305_pull failed with -1

As per the documentation, this means that the ciphertext is invalid.

But I'm not sure what is amiss here. Would be great if you could help out. Thank you!

vishnukvmd commented 3 years ago

Looks like my understanding of Dart's I/O APIs was lacking. Fixed the problem by simply using the correct one to append to a file (https://github.com/ente-io/frame/commit/e574a0d8d22e5eb8f082df98ab396086a1174f80).