jedisct1 / libsodium

A modern, portable, easy to use crypto library.
https://libsodium.org
Other
12.15k stars 1.73k forks source link

crypto_secretstream_xchacha20poly1305_pull failed with -1 #996

Closed vishnukvmd closed 3 years ago

vishnukvmd commented 3 years ago

Firstly, thank you for libsodium, it has been a life saver.

I'm currently using flutter_sodium and am 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 first 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!

enkore commented 3 years ago

I'd first check if this is some kind of I/O problem (e.g. high level I/O library doing weird things to strings containing binary data), then take a look at the offset/size calculations (I never get them right on the first try), e.g. unroll the loop for one to two iterations and use a file for testing that fits within that.

vishnukvmd commented 3 years ago

Yes, 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).