decodeOpenSshPrivate static method
Implementation
static ({Uint8List seed, Uint8List publicKey, String comment})
decodeOpenSshPrivate(Uint8List bytes) {
final magic = utf8.encode('openssh-key-v1\u0000');
if (bytes.length < magic.length ||
!constantTimeAreEqual(
Uint8List.fromList(bytes.sublist(0, magic.length)),
Uint8List.fromList(magic),
)) {
throw ArgumentError('Formato OpenSSH private key invalido');
}
var off = magic.length;
final cipher = _readSshString(bytes, off);
off = cipher.nextOffset;
final kdf = _readSshString(bytes, off);
off = kdf.nextOffset;
final kdfOpts = _readSshString(bytes, off);
off = kdfOpts.nextOffset;
final nKeys = _readU32(bytes, off);
off += 4;
if (utf8.decode(cipher.value) != 'none' ||
utf8.decode(kdf.value) != 'none' ||
kdfOpts.value.isNotEmpty ||
nKeys != 1) {
throw UnsupportedError('Somente OpenSSH sem criptografia (none/none)');
}
final publicBlob = _readSshString(bytes, off);
off = publicBlob.nextOffset;
final privateBlob = _readSshString(bytes, off);
off = privateBlob.nextOffset;
if (off != bytes.length) {
throw ArgumentError('Bytes extras em OpenSSH private key');
}
var p = 0;
final check1 = _readU32(privateBlob.value, p);
p += 4;
final check2 = _readU32(privateBlob.value, p);
p += 4;
if (check1 != check2) {
throw ArgumentError('Checkints OpenSSH invalidos');
}
final type = _readSshString(privateBlob.value, p);
p = type.nextOffset;
if (utf8.decode(type.value) != 'ssh-ed25519') {
throw UnsupportedError('Tipo OpenSSH nao suportado');
}
final pub = _readSshString(privateBlob.value, p);
p = pub.nextOffset;
final priv = _readSshString(privateBlob.value, p);
p = priv.nextOffset;
final comment = _readSshString(privateBlob.value, p);
p = comment.nextOffset;
if (pub.value.length != 32 || priv.value.length != 64) {
throw ArgumentError('Material Ed25519 invalido em OpenSSH');
}
final seed = Uint8List.fromList(priv.value.sublist(0, 32));
final pubFromPriv = Uint8List.fromList(priv.value.sublist(32, 64));
if (!constantTimeAreEqual(pub.value, pubFromPriv)) {
throw ArgumentError('Chave publica inconsistente no OpenSSH private key');
}
final pad = privateBlob.value.sublist(p);
for (var i = 0; i < pad.length; i++) {
if (pad[i] != (i + 1)) {
throw ArgumentError('Padding OpenSSH invalido');
}
}
final pubFromHeader = _parsePublicBlob(publicBlob.value);
if (!constantTimeAreEqual(pub.value, pubFromHeader)) {
throw ArgumentError('Chave publica header/private mismatch');
}
final cmt = utf8.decode(comment.value, allowMalformed: true);
return (seed: seed, publicKey: Uint8List.fromList(pub.value), comment: cmt);
}