Skip to content
This repository has been archived by the owner on Jan 20, 2023. It is now read-only.

Argon2id in sensitive mode gives SodiumException crypto_pwhash failed with -1 #65

Open
java-crypto opened this issue Aug 18, 2021 · 2 comments

Comments

@java-crypto
Copy link

I'm using Flutter_Sodium version 0.2.0 and tried to generate an Argon2id13 password hash using the sensitive parameter set.

My system parameter were:

Flutter 2.2.1
Dart 2.13.1
Sodium version: 1.0.18
Android 11: sdk_gphone_x86_arm-userdebug 11 RSR1.201013.001 6903271 dev-keys

This is the code I used to generate the hash (the full code follows at the end):

printC('Generate a 32 byte long encryption key with Argon2id in sensitive mode');
printC('Sodium version: ' + Sodium.versionString);
printC('Dart version: ' + Platform.version);
final passphrase = 'secret passphrase';
printC('passphrase: ' + passphrase);
var salt16Byte = generateSalt16Byte();
printC('salt (Base64): ' + base64Encoding(salt16Byte));
final outlen = 32;
final passwd = utf8.encoder.convert(passphrase);
final opslimit = Sodium.cryptoPwhashOpslimitSensitive;
final memlimit = Sodium.cryptoPwhashMemlimitSensitive;
final alg = Sodium.cryptoPwhashAlgArgon2id13;
printC('opsLimit: ' + Sodium.cryptoPwhashOpslimitSensitive.toString());
printC('memLimit: ' + Sodium.cryptoPwhashMemlimitSensitive.toString());
final hash =
Sodium.cryptoPwhash(outlen, passwd, salt16Byte, opslimit, memlimit, alg);
printC('hash (Base64): ' + base64Encoding(hash));

I'm using the constants Sodium.cryptoPwhashOpslimitSensitive and Sodium.cryptoPwhashMemlimitSensitive for opsLimit and memLimit.

The code fails with an Exception caught by gesture: SodiumException crypto_pwhash failed with -1 (full stack see below:):

I/flutter ( 9661): Generate a 32 byte long encryption key with Argon2id in sensitive mode
I/flutter ( 9661): Sodium version: 1.0.18
I/flutter ( 9661): Dart version: 2.13.1 (stable) (Fri May 21 12:45:36 2021 +0200) on "android_ia32"
I/flutter ( 9661): passphrase: secret passphrase
I/flutter ( 9661): salt (Base64): tVcZQuWbpNxGrvJ45H5Q8Q==
I/flutter ( 9661): opsLimit: 4
I/flutter ( 9661): memLimit: 1073741824

======== Exception caught by gesture ===============================================================
The following SodiumException object was thrown while handling a gesture:
  crypto_pwhash failed with -1

When the exception was thrown, this was the stack:
#0      Result.mustSucceed (package:flutter_sodium/src/extensions.dart:48:7)
#1      Sodium.cryptoPwhash (package:flutter_sodium/src/sodium.dart:1087:12)
#2      _MyWidgetState.runYourMainDartCode (package:dartprojectspointycastle/CrossPlatformCryptography/LibsodiumArgon2idSensitiveIssue.dart:136:12)
#3      _MyWidgetState.build.<anonymous closure> (package:dartprojectspointycastle/CrossPlatformCryptography/LibsodiumArgon2idSensitiveIssue.dart:82:21)
#4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:989:21)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#87d41
  debugOwner: GestureDetector
  state: possible
  won arena
  finalPosition: Offset(300.3, 727.6)
  finalLocalPosition: Offset(35.2, 10.3)
  button: 1
  sent tap down
====================================================================================================

full code (it's a simple console app, just press "run the code"):

import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter_sodium/flutter_sodium.dart';

void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Console'),
        ),
        body: MyWidget(),
      ),
    );
  }
}

// widget class
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  // state variable
  String _textString = 'press the button "run the code"';
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(
          'console output',
          style: TextStyle(fontSize: 30),
        ),
        Expanded(
          flex: 1,
          child: new SingleChildScrollView(
            scrollDirection: Axis.vertical,
            child: Padding(
                padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
                child: Text(_textString,
                    style: TextStyle(
                      fontSize: 20.0,
                      fontWeight: FontWeight.bold,
                      fontFamily: 'Courier',
                      color: Colors.black,
                    ))),
          ),
        ),
        Container(
          child: Row(
            children: <Widget>[
              SizedBox(width: 10),
              Expanded(
                child: ElevatedButton(
                  child: Text('clear console'),
                  onPressed: () {
                    clearConsole();
                  },
                ),
              ),
              SizedBox(width: 10),
              Expanded(
                child: ElevatedButton(
                  child: Text('extra Button'),
                  onPressed: () {
                    runYourSecondDartCode();
                  },
                ),
              ),
              SizedBox(width: 10),
              Expanded(
                child: ElevatedButton(
                  child: Text('run the code'),
                  onPressed: () {
                    runYourMainDartCode();
                  },
                ),
              ),
              SizedBox(width: 10),
            ],
          ),
        ),
      ],
    );
  }

  void clearConsole() {
    setState(() {
      _textString = ''; // will add additional lines
    });
  }

  void printC(_newString) {
    setState(() {
      _textString =
          _textString + _newString + '\n';
    });
    print(_newString); // extra output on Console
  }
  /* ### instructions ###
      place your code inside runYourMainDartCode and print it to the console
      using printC('your output to the console');
      clearConsole() clears the actual console
      place your code that needs to be executed additionally inside
      runYourSecondDartCode and start it with "extra Button"
   */
  void runYourMainDartCode() {

    clearConsole();
    printC('Generate a 32 byte long encryption key with Argon2id in sensitive mode');

    printC('Sodium version: ' + Sodium.versionString);
    printC('Dart version: ' + Platform.version);

    final passphrase = 'secret passphrase';
    printC('passphrase: ' + passphrase);

    var salt16Byte = generateSalt16Byte();
    printC('salt (Base64): ' + base64Encoding(salt16Byte));

    final outlen = 32;
    final passwd = utf8.encoder.convert(passphrase);
    final opslimit = Sodium.cryptoPwhashOpslimitSensitive;
    final memlimit = Sodium.cryptoPwhashMemlimitSensitive;
    final alg = Sodium.cryptoPwhashAlgArgon2id13;
    printC('opsLimit: ' + Sodium.cryptoPwhashOpslimitSensitive.toString());
    printC('memLimit: ' + Sodium.cryptoPwhashMemlimitSensitive.toString());
    final hash =
    Sodium.cryptoPwhash(outlen, passwd, salt16Byte, opslimit, memlimit, alg);
    printC('hash (Base64): ' + base64Encoding(hash));
  }

  Uint8List generateSalt16Byte() {
    return Sodium.randombytesBuf(16);
  }

  String base64Encoding(Uint8List input) {
    return base64.encode(input);
  }

  void runYourSecondDartCode() {
    printC('execute additional code');
  }
}

@kozw
Copy link
Contributor

kozw commented Aug 18, 2021

You probably exceed the memory limitations of the OS. I believe the sensitive parameter uses 1Gb of memory, not sure where Android likes that. Try a more moderate parameter set.

@java-crypto
Copy link
Author

@kozw: Thanks for your comment. As I'm writing "cross platform cryptography" routines, I've checked the lower parameter sets against Java etc. and they are working as expected with equal results. The "sensitive" has of course the most resource expectations, but as the library is build for Android OS there should be (minimum) a warning or a "stopper" to avoid those errors.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants