繁体   English   中英

如何在飞镖中将 AsymmetricKeyPair 转换为 base64 编码字符串

[英]how to convert AsymmetricKeyPair to base64 encoding string in dart

我是 PointyCastle 的新手,如何在 dart 中使用 PointyCastle 生成 ecc base64密钥对

AsymmetricKeyPair<PublicKey, PrivateKey> generateKeyPair({curve = 'secp256r1'}) {
    var param = curve == 'secp256r1' ? ECCurve_secp256r1() : ECCurve_secp256k1();
    var keyParams = ECKeyGeneratorParameters(param);

    var random = FortunaRandom();
    random.seed(KeyParameter(_seed()));

    var generator = ECKeyGenerator();
    generator.init(ParametersWithRandom(keyParams, random));

    return generator.generateKeyPair();
}
Uint8List _seed() {
    var random = Random.secure();
    var seed = List<int>.generate(32, (_) => random.nextInt(256));
    return Uint8List.fromList(seed);
}

上面我可以生成一个 AsymmetricKeyPair 对象,如何像我已经完成的 js 包一样获取公共 base64 和私有 base64

{"priKey":"CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=","pubKey":"BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM="}

此外,起初我想在flutter android中使用我的js包文件,但据我所知,这将非常困难

如何在flutter android中使用js包

我还需要在 sha256 中使用 ecdsa 进行签名和验证功能

Signer signer = new Signer('SHA-256/ECDSA');
// 签名,参数:私钥,明文
ECSignature sign(String privateKeyStr, String txt) {
    SecureRandom random = _setRadom();
    // how to convert a plain txt to kTestBytes
    final Uint8List kTestBytes = new Uint8List.fromList([1, 2, 3]);

    // if I pass in base64 privateKey str, is the radix 64?
    ECPrivateKey privateKey = new ECPrivateKey(BigInt.parse(privateKeyStr, radix: 10), ecDomain);

    PrivateKeyParameter signParams = new PrivateKeyParameter(privateKey);
    signer.init(true, new ParametersWithRandom(signParams, random));
    ECSignature signature = signer.generateSignature(kTestBytes) as ECSignature;
    return signature;
}
// 验签
//  参数: 明文,签名,公钥
bool verify(txt, signature, publicKey) {
    // how to make the txt to kTestBytes
    var kTestBytes = txt
    signer.init(false, new PublicKeyParameter(publicKey));
    bool verify = signer.verifySignature(kTestBytes, signature);
    // print(verify);
    return verify;
}
// I don't know what this function actually do,as I know in other language ecdsa don;t need a random number.
SecureRandom _setRadom() {
    List<int> key = [67, 3, 241, 75, 143, 78, 115, 99, 21, 242, 180, 43, 26, 7, 194, 20];
    List<int> iv = [87, 117, 137, 182, 2, 199, 132, 230, 120, 12, 109, 177, 34, 197, 186, 206];
    KeyParameter keyParam = new KeyParameter(new Uint8List.fromList(key));
    ParametersWithIV<KeyParameter> paramsIV = new ParametersWithIV(keyParam, new Uint8List.fromList(iv));
    SecureRandom random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')..seed(paramsIV);
    return random;
}

我在任何地方都可以找到示例代码,这些功能被互联网上的一些副本更改。我在评论中得到了很多混淆列表

EC 密钥将作为 Base64 编码的原始私钥和 Base64 编码的原始未压缩公钥导出/导入。

首先可以说,当生成新的密钥对时,使用发布的代码进行签名和验证是有效的:

AsymmetricKeyPair<PublicKey, PrivateKey> kp = generateKeyPair();
ECSignature signature = sign(kp.privateKey as ECPrivateKey, "The quick brown fox jumps over the lazy dog");
bool verified = verify("The quick brown fox jumps over the lazy dog", signature, kp.publicKey as ECPublicKey);
print(verified); // true

即在下面我将重点介绍密钥的导入/导出。 原始密钥封装在ECPrivateKeyECPublicKey中,可以按如下方式导出和导入:

String p256 = 'secp256r1';
AsymmetricKeyPair<PublicKey, PrivateKey> kp = generateKeyPair(curve: p256);

// Export
BigInt d = (kp.privateKey as ECPrivateKey).d!;
BigInt x = (kp.publicKey as ECPublicKey).Q!.x!.toBigInteger()!;
BigInt y = (kp.publicKey as ECPublicKey).Q!.y!.toBigInteger()!;

// Import
ECDomainParameters domain = ECDomainParameters(p256);
ECPrivateKey ecPrivateKey = ECPrivateKey(d, domain);
ECPublicKey ecPublicKey = ECPublicKey(domain.curve.createPoint(x, y), domain);

这里d是原始私钥, xy是原始公钥的 x 和 y 坐标。


在 JavaScript 端,使用 Base64 编码的原始私钥和 Base64 编码的原始未压缩密钥,其中未压缩密钥是串联0x04 + <x> + <y> 因此,对于导出和导入,以下适用:

  • 关于导出,Base64 编码的原始私钥和公钥可以从dxy派生如下:

     String rawPrivateB64 = exportPrivate(d); String rawUncompressedPublicB64 = exportPublic(x, y, 32);

    import 'dart:convert'; import 'package:nanodart/nanodart.dart'; String exportPrivate(BigInt d){ return base64Encode(NanoHelpers.bigIntToBytes(d)); } String exportPublic(BigInt x, BigInt y, int size){ return base64Encode(NanoHelpers.concat([Uint8List.fromList([4]), pad(NanoHelpers.bigIntToBytes(x), size), pad(NanoHelpers.bigIntToBytes(y), size)])); } Uint8List pad(Uint8List list, int size){ Uint8List padded = list; int currSize = list.length; if (currSize < size){ Uint8List pad = Uint8List(size - currSize); padded = NanoHelpers.concat([pad, list]); } return padded; }

    作为第三个参数传入exportPublic()的大小是生成器点的顺序大小(secp256r1 为 32 字节)。 如果xy更小,则它们各自从前面用 0x00 值填充,直到达到所需的长度。

    对于从BigIntUint8List的转换以及连接,为了简单起见,我使用了NanoDart包中的NanoHelpers类。 当然,这里也可以使用其他实现方式。

  • 关于导入, dxy可以从 Base64 编码的原始私钥和公钥导出,如下所示:

     BigInt d = importPrivate(rawPrivateB64); List xy = importPublic(rawUncompressedPublicB64); BigInt x = xy.elementAt(0); BigInt y = xy.elementAt(1);

    BigInt importPrivate(String d){ return NanoHelpers.byteToBigInt(base64Decode(d)); } List importPublic(String xy){ Uint8List xyBytes = base64Decode(xy); xyBytes = xyBytes.sublist(1, xyBytes.length); int size = xyBytes.length ~/ 2; Uint8List x = xyBytes.sublist(0, size); Uint8List y = xyBytes.sublist(size); return [NanoHelpers.byteToBigInt(x), NanoHelpers.byteToBigInt(y)]; }

测试

发布的密钥对

{"priKey":"CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=","pubKey":"BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM="}

可以导入并用于签名和验证,如下所示:

String rawPrivateB64 = "CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=";
String rawUncompressedPublicB64 = "BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM=";

BigInt d = importPrivate(rawPrivateB64);
List xy = importPublic(rawUncompressedPublicB64);
BigInt x = xy.elementAt(0);
BigInt y = xy.elementAt(1);

ECDomainParameters domain = ECDomainParameters('secp256r1');
ECPrivateKey private = ECPrivateKey(d, domain);
ECPublicKey public = ECPublicKey(domain.curve.createPoint(x, y), domain);

ECSignature signature = sign(private, "The quick brown fox jumps over the lazy dog");
bool verified = verify("The quick brown fox jumps over the lazy dog", signature, public);
print(verified); // true

编辑:关于您的评论: sign()verify()是您发布的方法,但根据更改,现在直接传递键(而不是字符串)并应用实际消息(而不是[1,2,3] ) 使用utf8.encode()进行 UTF-8 编码:

import 'dart:convert';

ECSignature sign(ECPrivateKey privateKey, String txt) {
  SecureRandom random = _setRandom();
  Uint8List txtBytes = Uint8List.fromList(utf8.encode(txt));
  PrivateKeyParameter signParams = PrivateKeyParameter(privateKey);
  signer.init(true, ParametersWithRandom(signParams, random));
  ECSignature signature = signer.generateSignature(txtBytes) as ECSignature;
  return signature;
}

bool verify(String txt, ECSignature signature, ECPublicKey publicKey) {
  signer.init(false, PublicKeyParameter(publicKey));
  bool verify = signer.verifySignature(Uint8List.fromList(utf8.encode(txt)), signature);
  return verify;
}

作为_setRandom()我应用了generateKeyPair()的实现而不是您的实现(即基于FortunaRandom()的 CSPRNG)。

我的整个代码基于接受的答案

加密飞镖

import "dart:typed_data";
import "dart:math";
import 'dart:convert';

import "package:pointycastle/export.dart";
import './utils.dart';

Signer signer = new Signer('SHA-256/ECDSA');

class Crypto {
  final ECDomainParameters ecDomain = new ECDomainParameters('secp256r1');

  /// 公私钥对生成
  /// 关于公私钥encoding:https://stackoverflow.com/questions/72641616/how-to-convert-asymmetrickeypair-to-base64-encoding-string-in-dart
  ///

  Map generateKeyPair({curve = 'secp256r1'}) {
    var param = curve == 'secp256r1' ? ECCurve_secp256r1() : ECCurve_secp256k1();
    var keyParams = ECKeyGeneratorParameters(param);

    var random = FortunaRandom();
    random.seed(KeyParameter(this._seed(32)));

    var generator = ECKeyGenerator();
    generator.init(ParametersWithRandom(keyParams, random));

    AsymmetricKeyPair<PublicKey, PrivateKey> kp = generator.generateKeyPair();
    BigInt d = (kp.privateKey as ECPrivateKey).d!;
    BigInt x = (kp.publicKey as ECPublicKey).Q!.x!.toBigInteger()!;
    BigInt y = (kp.publicKey as ECPublicKey).Q!.y!.toBigInteger()!;
    String rawPrivateB64 = exportPrivate(d);
    String rawUncompressedPublicB64 = exportPublic(x, y, 32);
    return {'base64Pub': rawUncompressedPublicB64, 'base64Priv': rawPrivateB64};
  }

  Uint8List _seed(size) {
    var random = Random.secure();
    var seed = List<int>.generate(size, (_) => random.nextInt(256));
    return Uint8List.fromList(seed);
  }

// TODO
// Restore the ECPrivateKey from 'd'.
  restoreKeyFromPrivate(privateKeyStr) {
    ECPrivateKey privateKey = new ECPrivateKey(BigInt.parse(privateKeyStr, radix: 10), ecDomain);
    ECPoint Q = privateKey.parameters!.G * privateKey.d as ECPoint;
    ECPublicKey publicKey = new ECPublicKey(Q, privateKey.parameters);
    return publicKey;
  }

  ECSignature sign(ECPrivateKey privateKey, String txt) {
    SecureRandom random = _setRandom();
    Uint8List txtBytes = Uint8List.fromList(utf8.encode(txt));
    PrivateKeyParameter signParams = PrivateKeyParameter(privateKey);
    signer.init(true, ParametersWithRandom(signParams, random));
    ECSignature signature = signer.generateSignature(txtBytes) as ECSignature;
    return signature;
  }

  bool verify(String txt, ECSignature signature, ECPublicKey publicKey) {
    signer.init(false, PublicKeyParameter(publicKey));
    bool verify = signer.verifySignature(Uint8List.fromList(utf8.encode(txt)), signature);
    return verify;
  }

  SecureRandom _setRandom() {
    // List<int> key = [67, 3, 241, 75, 143, 78, 115, 99, 21, 242, 180, 43, 26, 7, 194, 20];
    // List<int> iv = [87, 117, 137, 182, 2, 199, 132, 230, 120, 12, 109, 177, 34, 197, 186, 206];
    List<int> key = _seed(16);
    List<int> iv = _seed(16);
    KeyParameter keyParam = new KeyParameter(new Uint8List.fromList(key));
    ParametersWithIV<KeyParameter> paramsIV = new ParametersWithIV(keyParam, new Uint8List.fromList(iv));
    SecureRandom random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')..seed(paramsIV);
    return random;
  }
}

crypto_test.dart

import '../lib/crypto/crypto.dart';
import "dart:typed_data";
import "dart:math";
import '../lib/crypto/utils.dart';
import "package:pointycastle/export.dart";

var crypto = new Crypto();
void main() {
  // _generateTest();
  // _signTest();
  Map keyPair = crypto.generateKeyPair();
  String rawPrivateB64 = keyPair['base64Priv'];
  String rawUncompressedPublicB64 = keyPair['base64Pub'];

  BigInt d = importPrivate(rawPrivateB64);
  List xy = importPublic(rawUncompressedPublicB64);
  BigInt x = xy.elementAt(0);
  BigInt y = xy.elementAt(1);

  ECDomainParameters domain = ECDomainParameters('secp256r1');
  ECPrivateKey private = ECPrivateKey(d, domain);
  ECPublicKey public = ECPublicKey(domain.curve.createPoint(x, y), domain);

  ECSignature signature = crypto.sign(private, "The quick brown fox jumps over the lazy dog");
  bool verified = crypto.verify("The quick brown fox jumps over the lazy dog", signature, public);
  print('验签结果');
  print(verified); // true
}

_generateTest() {
  Map keyPair = crypto.generateKeyPair();

  print("结果");
  print(keyPair['base64Pub']);
  print(keyPair['base64Priv']);
}

_signTest() {
  // AsymmetricKeyPair<PublicKey, PrivateKey> kp = crypto.generateKeyPair();
  // ECSignature signature = sign(kp.privateKey as ECPrivateKey, "The quick brown fox jumps over the lazy dog");
  // bool verified = crypto.verify("The quick brown fox jumps over the lazy dog", signature, kp.publicKey as ECPublicKey);
  // print(verified); // true
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM