publicKeyDecode function Null safety

PublicKey publicKeyDecode (
  1. String str,
  2. {int offset = 0,
  3. bool allowPreamble = false}
)

Decodes the first public key from text.

Whitespace before the public key is ignored. By default, any non-whitespace preamble before the key is not allowed. To ignore non-whitespace preamble, set allowPreamble to true. Note: not all formats allow preamble.

Result

Returns first public key in str, starting at offset (or the beginning of the string if no offset is provided).

Returns a Pointy Castle PublicKey, which is an abstract class. The program should determine what the actual type is and then cast it into that type. For example,

final k = publicKeyDecode(str);
if (k is RSAPublicKeyWithInfo) {
  final rsaKey = k as RSAPublicKeyWithInfo;
  // use the public key
}

The text before and after the public key can be identified by examining the source member in the result (after casting it into its actual type).

Exceptions

A KeyMissing is thrown if no public key is found.

A KeyBad is thrown if the private key is invalid.

A KeyUnsupported is thrown if the type of public key is not supported.

See also

This method decodes one public key. If multiple public keys are expected in the string use the publicKeyDecodeAll method.

Implementation

pointy_castle.PublicKey publicKeyDecode(String str,
    {int offset = 0, bool allowPreamble = false}) {
  if (offset < 0) {
    throw ArgumentError.value(offset, 'offset', 'is negative');
  }
  var p = offset;

  // Skip leading whitespace

  while (p < str.length) {
    final ch = str[p];
    if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
      p++;
    } else {
      break;
    }
  }

  // Try OpenSSH format (since it is the only one that cannot skip preamble)

  if (str.startsWith('ssh-', p)) {
    // Assume it is OpenSSH format

    final openSsh = OpenSshPublicKey.decode(str, offset: p);

    // The comment (if any) is included as a header
    final headers = <SshPublicKeyHeader>[];

    final c = openSsh.comment;
    if (c != null) {
      headers.add(SshPublicKeyHeader(SshPublicKeyHeader.commentTag, c));
    }

    return _keyFromOpenSshChunksAndHeaders(
        openSsh.data, headers, openSsh.source);
  }

  // Fall through to try remaining formats
  // They all must start with four or five hyphens

  final fourHyphens = str.indexOf('----', p);
  if (0 <= fourHyphens) {
    p = fourHyphens;

    if (str.startsWith(SshPublicKey.beginMarker, p)) {
      // Assume it is the SSH Public Key File Format (RFC 4716)
      final spk =
          SshPublicKey.decode(str, offset: p, allowPreamble: allowPreamble);

      return _keyFromOpenSshChunksAndHeaders(
          spk.bytes, spk.headers, spk.source);
    }

    // Fall through to try Textual Encoding formats

    final block =
        TextualEncoding.decode(str, offset: p, allowPreamble: allowPreamble);

    if (block.label == 'RSA PUBLIC KEY') {
      // Data is PKCS #1 (which always an RSA public key)

      final pkcs1 = Pkcs1RsaPublicKey.decode(block.data,
          PubTextSource.setEncoding(block.source!, PubKeyEncoding.pkcs1));

      return _rsaFromPkcs1(pkcs1);
    } else if (block.label == 'PUBLIC KEY') {
      // Data is subjectPublicKeyInfo

      final spki = SubjectPublicKeyInfo.decode(block.data,
          source: PubTextSource.setEncoding(
              block.source!, PubKeyEncoding.x509spki));

      if (spki.algorithmOid == _rsaAlgorithmOid) {
        // RSA public key

        assert(spki.algorithmParameters.length == 1 &&
            spki.algorithmParameters.first is ASN1Null);

        final pkcs1 = Pkcs1RsaPublicKey.decode(spki.data, spki.source);

        return _rsaFromPkcs1(pkcs1);
      } else {
        throw KeyUnsupported('unsupported algorithm: ${spki.algorithmOid}');
      }
    } else {
      throw KeyUnsupported('unsupported label: ${block.label}');
    }
  }

  throw KeyMissing('no key found');
}