mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-29 02:07:39 +08:00
Extend poc for generating ssh keys via dart
Still needs work
This commit is contained in:
230
lib/main2.dart
230
lib/main2.dart
@ -1,3 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
@ -21,6 +22,10 @@ void main() {
|
||||
|
||||
var priv = encrypter.encodeKeyToString(privateKey);
|
||||
print("Priv: $priv");
|
||||
|
||||
print("");
|
||||
var s = output(publicKey, "vish");
|
||||
print(s);
|
||||
}
|
||||
|
||||
SecureRandom _getSecureRandom() {
|
||||
@ -46,3 +51,228 @@ AsymmetricKeyPair<PublicKey, PrivateKey> _getRsaKeyPair(
|
||||
keyGenerator.init(params);
|
||||
return keyGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
String output(RSAPublicKey key, String comment) {
|
||||
var data = BinaryLengthValue.encode([
|
||||
BinaryLengthValue.fromString("ssh-rsa"),
|
||||
BinaryLengthValue.fromBigInt(key.exponent),
|
||||
BinaryLengthValue.fromBigInt(key.modulus),
|
||||
]);
|
||||
|
||||
if (comment.isNotEmpty) {
|
||||
comment = comment.replaceAll('\r', ' ');
|
||||
comment = comment.replaceAll('\n', ' ');
|
||||
comment = ' $comment';
|
||||
}
|
||||
|
||||
return 'ssh-rsa ${base64.encode(data)}$comment';
|
||||
}
|
||||
|
||||
/*
|
||||
const BIGNUM *pRsa_mod = NULL;
|
||||
const BIGNUM *pRsa_exp = NULL;
|
||||
|
||||
RSA_get0_key(pRsa, &pRsa_mod, &pRsa_exp, NULL);
|
||||
|
||||
// reading the modulus
|
||||
int nLen = BN_num_bytes(pRsa_mod);
|
||||
nBytes = (unsigned char *)malloc(nLen);
|
||||
ret = BN_bn2bin(pRsa_mod, nBytes);
|
||||
if (ret <= 0)
|
||||
goto cleanup;
|
||||
|
||||
// reading the public exponent
|
||||
int eLen = BN_num_bytes(pRsa_exp);
|
||||
eBytes = (unsigned char *)malloc(eLen);
|
||||
if (eBytes == NULL)
|
||||
{
|
||||
gj_log_internal("write_rsa_public_key malloc failed. Length: %d", eLen);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
ret = BN_bn2bin(pRsa_exp, eBytes);
|
||||
if (ret <= 0)
|
||||
goto cleanup;
|
||||
|
||||
encodingLength = 11 + 4 + eLen + 4 + nLen;
|
||||
// correct depending on the MSB of e and N
|
||||
if (eBytes[0] & 0x80)
|
||||
encodingLength++;
|
||||
if (nBytes[0] & 0x80)
|
||||
encodingLength++;
|
||||
|
||||
pEncoding = (unsigned char *)malloc(encodingLength);
|
||||
memset(pEncoding, 0, encodingLength);
|
||||
memcpy(pEncoding, pSshHeader, 11);
|
||||
|
||||
index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
|
||||
SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
|
||||
|
||||
b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
pFile = fopen(file_path, "w");
|
||||
bio = BIO_new_fp(pFile, BIO_CLOSE);
|
||||
BIO_printf(bio, "ssh-rsa ");
|
||||
bio = BIO_push(b64, bio);
|
||||
BIO_write(bio, pEncoding, encodingLength);
|
||||
BIO_flush(bio);
|
||||
bio = BIO_pop(b64);
|
||||
BIO_printf(bio, " %s\n", comment);
|
||||
BIO_flush(bio);
|
||||
BIO_free_all(bio);
|
||||
BIO_free(b64);
|
||||
*/
|
||||
|
||||
class BinaryLengthValue {
|
||||
//================================================================
|
||||
// Constructors
|
||||
|
||||
//----------------------------------------------------------------
|
||||
/// Create a length-value for a sequence of bytes.
|
||||
|
||||
BinaryLengthValue(Uint8List bytes) : _dataBytes = bytes;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
/// Create a length-value for a multiple precision integer.
|
||||
///
|
||||
/// See section 5 of
|
||||
/// [RFC 4251](https://tools.ietf.org/html/rfc4251#section-5) for a definition
|
||||
/// of this format.
|
||||
|
||||
BinaryLengthValue.fromBigInt(BigInt value) : _dataBytes = _encodeMPInt(value);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
/// Create a length plus bytes for a string.
|
||||
///
|
||||
/// The string is encoded using the [encoding], which defaults to utf8.
|
||||
/// This default works for US-ASCII too if the value can be guaranteed to only
|
||||
/// contain US-ASCII characters, since US-ASCII is a subset of utf8.
|
||||
|
||||
BinaryLengthValue.fromString(String value, {Encoding encoding = utf8})
|
||||
: _dataBytes = Uint8List.fromList(encoding.encode(value));
|
||||
|
||||
//================================================================
|
||||
// Members
|
||||
|
||||
/// The bytes making up the value. That is, without the length bytes.
|
||||
|
||||
final Uint8List _dataBytes;
|
||||
|
||||
//================================================================
|
||||
// Static methods
|
||||
|
||||
//----------------------------------------------------------------
|
||||
/// Encodes a sequence of length-value.
|
||||
///
|
||||
/// Returns a sequence of bytes that contains each of the [items] in order.
|
||||
/// Each of those items is represented by a length followed by the bytes
|
||||
/// of the item. The length is always four bytes: a big-endian unsigned 32-bit
|
||||
/// integer.
|
||||
|
||||
static Uint8List encode(Iterable<BinaryLengthValue> items) {
|
||||
final bytes = <int>[];
|
||||
|
||||
for (final chunk in items) {
|
||||
// Chunk length (4-byte big-endian)
|
||||
final n = chunk._dataBytes.length;
|
||||
bytes
|
||||
..add((n >> 24) & 0xFF)
|
||||
..add((n >> 16) & 0xFF)
|
||||
..add((n >> 8) & 0xFF)
|
||||
..add((n >> 0) & 0xFF)
|
||||
..addAll(chunk._dataBytes);
|
||||
}
|
||||
|
||||
return Uint8List.fromList(bytes);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
/// Encode a multiple precision integer.
|
||||
///
|
||||
/// Returns a sequence of bytes that represents the [value] as a multiple
|
||||
/// precision integer. See section 5 of
|
||||
/// [RFC 4251](https://tools.ietf.org/html/rfc4251#section-5) for a definition
|
||||
/// of this format.
|
||||
///
|
||||
/// Note: the returned value is just the number and does not have any bytes
|
||||
/// to indicate its length.
|
||||
|
||||
static Uint8List _encodeMPInt(BigInt value) {
|
||||
if (value == BigInt.zero) {
|
||||
return Uint8List(0); // no bytes in representation
|
||||
} else if (!value.isNegative) {
|
||||
// Positive multiple precision integer
|
||||
|
||||
var e = value;
|
||||
|
||||
final numBytes = 2 + ((e.bitLength - 1) ~/ 8);
|
||||
final bytes = Uint8List(numBytes);
|
||||
|
||||
// Extract each byte of the number, starting with least-significant-byte
|
||||
// (the right most byte and working back to the beginning)
|
||||
|
||||
var i = numBytes - 1;
|
||||
|
||||
while (1 <= i) {
|
||||
final b = e & BigInt.from(0xFF); // least significant byte
|
||||
e = e >> 8;
|
||||
bytes[i--] = b.toInt();
|
||||
}
|
||||
assert(e == BigInt.zero);
|
||||
|
||||
// The padding byte is only needed if the first real byte has its MSB set
|
||||
|
||||
bytes[0] = 0x00; // padding byte
|
||||
final start = (bytes[1] & 0x80 != 0) ? 0 : 1; // use padding byte or not
|
||||
|
||||
return bytes.sublist(start);
|
||||
} else {
|
||||
// Negative multiple precision integer: represent as twos-complement
|
||||
|
||||
final x = (value.abs() - BigInt.one).bitLength + 1;
|
||||
var bytesToHoldTwosComplement = x ~/ 8;
|
||||
if (x % 8 != 0) {
|
||||
bytesToHoldTwosComplement += 1; // to hold additional bits
|
||||
}
|
||||
assert(0 < bytesToHoldTwosComplement);
|
||||
|
||||
final msbContrib = BigInt.two.pow((bytesToHoldTwosComplement * 8) - 1);
|
||||
var e = value + msbContrib; // without negative MSB contribution
|
||||
assert(!e.isNegative);
|
||||
|
||||
final numBytes = bytesToHoldTwosComplement + 1;
|
||||
final bytes = Uint8List(numBytes);
|
||||
|
||||
// Encode e using ones-complement, starting with the
|
||||
// least-significant-byte
|
||||
// (the right most byte and working back to the beginning)
|
||||
|
||||
var i = numBytes - 1;
|
||||
|
||||
while (1 <= i) {
|
||||
final b = (e & BigInt.from(0xFF)); // least significant byte, bit-neg
|
||||
e = e >> 8;
|
||||
bytes[i--] = b.toInt();
|
||||
}
|
||||
assert(e == BigInt.zero);
|
||||
|
||||
// Incorporate negative 2 ^ (N - 1) factor
|
||||
|
||||
if (bytes[1] & 0x80 != 0x80) {
|
||||
// MSB on first byte is not set: can use it for the MSB
|
||||
bytes[1] |= 0x80; // set the MSB on the first byte
|
||||
return bytes.sublist(1); // result without the extra padding byte
|
||||
} else {
|
||||
// MSB on first byte is already set: need to use the padding byte
|
||||
bytes[0] = 0x80; // set the MSB on padding byte and zero the rest of it
|
||||
return bytes; // result is the padding byte and the other bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Also need a parser for this format
|
||||
// FIXME: Also need tests for this format
|
||||
// FIXME: Same for the private key format!
|
||||
// It's for the openssh format
|
||||
|
14
pubspec.lock
14
pubspec.lock
@ -29,6 +29,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
asn1lib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: asn1lib
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.4"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -626,6 +633,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.3"
|
||||
steel_crypt:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: steel_crypt
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.1+1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -37,6 +37,7 @@ dependencies:
|
||||
flutter_emoji: ">= 2.0.0"
|
||||
git_url_parse2: ^0.0.1
|
||||
synchronized: ^2.2.0
|
||||
steel_crypt: ^1.7.1+1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_launcher_icons: "^0.7.2"
|
||||
|
Reference in New Issue
Block a user