LrtcEnvelope.parse constructor

LrtcEnvelope.parse(
  1. Uint8List bytes
)

Parses bytes. Throws InvalidFormatException if they are not a valid LRTC envelope.

Implementation

factory LrtcEnvelope.parse(Uint8List bytes) {
  const notAnEnvelope = InvalidFormatException(
    'Input is not a valid LRTC envelope. '
    'Did you pass a plaintext model? Encrypt it first with '
    '`dart run litert_crypto encrypt`.',
  );
  if (bytes.length < fixedHeaderLength) throw notAnEnvelope;
  for (var i = 0; i < magic.length; i++) {
    if (bytes[i] != magic[i]) {
      // A wrong magic is usually a mistake worth diagnosing precisely: a
      // plaintext .tflite reaching the loader means the asset was bundled
      // without encryption — the security failure already happened at
      // build time, so name it instead of a generic format error.
      if (_looksLikeTflite(bytes)) {
        throw const InvalidFormatException(
          'This is a plaintext TensorFlow Lite model (TFL3), not an LRTC '
          'file — it was never encrypted. If it came from your app '
          "bundle, the asset's pubspec entry is missing the litert_crypto "
          'transformer; any release built this way ships the model in '
          'the clear.',
        );
      }
      throw notAnEnvelope;
    }
  }
  final version = bytes[4];
  if (version != currentVersion) {
    throw InvalidFormatException(
      version == 1
          ? 'This is a version 1 file, written by litert_crypto 0.1.0. The '
              'format changed in 0.2.0 — re-encrypt the model with the '
              'current CLI: `dart run litert_crypto encrypt`.'
          : 'Unsupported format version $version '
              '(supported: $currentVersion).',
    );
  }
  final labelLength = bytes[7];
  final headerLength = fixedHeaderLength + labelLength + ivLength;
  if (bytes.length < headerLength + tagLength) throw notAnEnvelope;

  final labelEnd = fixedHeaderLength + labelLength;
  return LrtcEnvelope(
    version: version,
    keyId: (bytes[5] << 8) | bytes[6],
    label: utf8.decode(
      Uint8List.sublistView(bytes, fixedHeaderLength, labelEnd),
      allowMalformed: true,
    ),
    header: Uint8List.sublistView(bytes, 0, headerLength),
    iv: Uint8List.sublistView(bytes, labelEnd, headerLength),
    sealed: Uint8List.sublistView(bytes, headerLength),
  );
}