首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在dart中将AsymmetricKeyPair转换为base64编码字符串

如何在dart中将AsymmetricKeyPair转换为base64编码字符串
EN

Stack Overflow用户
提问于 2022-06-16 06:53:57
回答 2查看 304关注 0票数 1

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

代码语言:javascript
复制
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。

代码语言:javascript
复制
{"priKey":"CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=","pubKey":"BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM="}

此外,一开始,我想使用我的js包文件在颤振的android,但这将是非常困难的,我知道。

how to use js bundle in flutter android

我还需要在sha256中使用ecdsa进行符号和验证功能。

代码语言:javascript
复制
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;
}

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-06-16 13:28:55

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

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

代码语言:javascript
复制
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中,可以按以下方式导出和导入:

代码语言:javascript
复制
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>。因此,对于出口和进口,适用以下规定:

关于导出,

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

字符串rawPrivateB64 = exportPrivate(d);字符串rawUncompressedPublicB64 = exportPublic(x,y,32);

使用

导入‘dart:转换’;导入‘包:nanodart/nanodart.dart’;字符串exportPrivate(BigInt d){返回base64Encode(NanoHelpers.bigIntToBytes(d));} String exportPublic(BigInt,BigInt y,int size){返回exportPublic(NanoHelpers.bigIntToBytes( x ),大小),pad(NanoHelpers.bigIntToBytes(y),size) );} Uint8List pad(Uint8List list,int size){ Uint8List pad= list;int currSize = list.length;如果(currSize < size){ Uint8List pad = Uint8List(size - currSize);pad= NanoHelpers.concat(pad,list);}返回衬垫;}

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){返回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);int NanoHelpers.byteToBigInt(x),NanoHelpers.byteToBigInt(y);}en19#

测试

已发布的密钥对

代码语言:javascript
复制
{"priKey":"CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=","pubKey":"BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM="}

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

代码语言:javascript
复制
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()是您发布的方法,但是根据更改,现在直接传递键(而不是字符串),并使用utf8.encode()为UTF-8编码应用实际消息(而不是[1,2,3]):

代码语言:javascript
复制
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)。

票数 2
EN

Stack Overflow用户

发布于 2022-06-20 07:25:52

我的全部代码都是基于公认的答案

crypto.dart

代码语言:javascript
复制
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

代码语言:javascript
复制
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
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72641616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档