Decrypt Modulr secure token

Issue

In my Flutter App I need to decrypt a secure token from the Modulr API.
First I need to generate a RSA key and Modulr will use it to generate a secure token.

When the token is generated I receive a encryptedSymmetricKey, a initialisationVector (iv) and a token I need to decrypt.

The encryptedSymmetricKey is encoded using RSA ECB cipher with OAEP and with a hash SHA-256.

Then with de decrypted encryptedSymmetricKey I can decrypt the token encoded with a AES GCM cipher with no padding.

I’m using the pointycastle package.

This is my code:

  /// DECRYPT SYMMETRIC KEY
  final p = OAEPEncoding.withSHA256(RSAEngine());

  p.init(false, PrivateKeyParameter<RSAPrivateKey>(modulrKey.keypair.privateKey.asPointyCastle));

  final decryptedSymetricKeyBytes = p.process(base64Decode(result.encryptedSymmetricKey));

  /// AES-GCM ALGO
  final algo = AesGcm.with128bits();

  /// DECODE INIT VECTOR
  final decodedIv = base64Decode(result.initialisationVector);

  /// AES KEY
  final aesKey = await algo.newSecretKeyFromBytes(decryptedSymetricKeyBytes);

  /// DECRYPT TOKEN
  final decodedToken = base64Decode(result.token);

  final secretBox = SecretBox(decodedToken, nonce: decodedIv, mac: Mac.empty);
  final decryptedTokenBytes = await algo.decrypt(secretBox, secretKey: aesKey);
  final decryptedToken = base64Encode(decryptedTokenBytes);

But when I execute it I get this error:

SecretBox has wrong message authentication code (MAC)

Any idea on how to solve that ?
Addtionnaly this is the Modlur documentation: https://modulr.readme.io/docs/retrieve-secure-card-details

Solution

The linked JavaScript and Java code show that decodedToken is the concatenation of the actual ciphertext and the 16 bytes GCM tag. However, since the cryptography package used in the Dart code processes the ciphertext and the tag independently, both portions must first be separated. Then they can be passed to SecretBox. The decrypted data must be UTF-8 decoded.

A possible fix is:

import 'dart:convert';
import 'package:cryptography/cryptography.dart';
...
// Separate ciphertext and tag
final decodedToken = base64Decode(result.token);
final token  = decodedToken.sublist(0, decodedToken.length - 16);
final tag = decodedToken.sublist(decodedToken.length - 16);
...
// Apply ciphertext and tag
final secretBox = SecretBox(token, nonce: decodedIv, mac: Mac(tag));
...
// Utf-8 decode
final decryptedToken = utf8.decode(decryptedTokenBytes);

With this, the posted Dart code is functionally identical to the linked JavaScript and Java code, respectively.

Answered By – Topaco

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *