decodePemBlocks function

List<List<int>> decodePemBlocks(
  1. PemLabel label,
  2. String pemString, {
  3. bool strict = false,
  4. bool unsafeIgnoreLabel = false,
})

Decode a String of one or more concatenated PEM blocks.

Returns a list of base64 decoded bytes for each PEM block matching the given label. An empty list if no correctly formatted PEM blocks is found in the given pemString. This method will not throw an exception on formatting errors.

The parser defaults to laxtextualmsg from RFC 7468, but if strict is true parser will require stricttextualmsg. It is generally safe to parse in non-strict mode, which just ignores whitespace and allows widely used label aliases.

If unsafeIgnoreLabel is set to true the decoding parser will ignore the label. This can be useful in certain legacy scenarios, but is generally discouraged as it could lead to unintended usages of keys.

*Example

import 'package:pem/pem.dart';

// Parse in non-strict mode (default) which ignores extra whitespace.
final blocks = decodePemBlocks(PemLabel.publicKey, """
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEn1LlwLN/KBYQRVH6HfIMTzfEqJOVztLe
kLchp2hi78cCaMY81FBlYs8J9l7krc+M4aBeCGYFjba+hiXttJWPL7ydlE+5UG4U
Nkn3Eos8EiZByi9DVsyfy9eejh+8AXgp
-----END PUBLIC KEY-----

  -----BEGIN PUBLIC KEY-----
  MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEn1LlwLN/KBYQRVH6HfIMTzfEqJOVztLe
  kLchp2hi78cCaMY81FBlYs8J9l7krc+M4aBeCGYFjba+hiXttJWPL7ydlE+5UG4U
  Nkn3Eos8EiZByi9DVsyfy9eejh+8AXgp
  -----END PUBLIC KEY-----
""");

// Print byte size of keys
print('1st public key has ${blocks[0].length} bytes');
print('2nd public key has ${blocks[1].length} bytes');

Implementation

List<List<int>> decodePemBlocks(
  PemLabel label,
  String pemString, {
  bool strict = false,
  bool unsafeIgnoreLabel = false,
}) {
  final labels = _labels[label];
  if (labels == null) {
    throw AssertionError('Unkown label');
  }

  // Pick a parser
  final p = strict ? stricttextualmsg : laxtextualmsg;

  // Create results
  final result = <List<int>>[];
  for (final r in p.allMatches(pemString, overlapping: false)) {
    final doc = r.cast<String>();
    final preLabel = doc[0];
    final data = doc[1];
    final postLabel = doc[2];

    // Pre and post label must match, unless we're in unsafe ignore label mode.
    if (preLabel != postLabel && !unsafeIgnoreLabel) {
      continue;
    }
    // Label much match an allowed alias, if not ignoring
    if (!labels.contains(preLabel) && !unsafeIgnoreLabel) {
      continue;
    }
    // Label much match canonical label name, if we're in strict mode
    if (strict && labels.first != preLabel && !unsafeIgnoreLabel) {
      continue;
    }

    try {
      result.add(base64.decode(data));
    } on Exception {
      continue; // Ignore malformed base64
    }
  }

  return result;
}