首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NBitcoin:密码学第2部分

NBitcoin:密码学第2部分

作者头像
飞翔的猪脚粉
发布2018-03-26 10:42:34
8250
发布2018-03-26 10:42:34
举报
文章被收录于专栏:代码乱弹代码乱弹

介绍

我第一篇关于NBitcoin的文章之后,我决定写一个面向.NET开发者的,关于NBitcoin比特币网关的系列文章。

本文将不涉及具体数学运算,以便您能理解总体思路和数据流。在本文的末尾,我会贴出一个链接,链接中的文章能把其中的数学原理讲的比我更通俗易懂。

在我的第一篇文章中,我介绍了关于比特币的基本运行原理,来帮助您花费您自己拥有的资金。

而这篇文章将介绍一些加强隐私和安全性的办法。

就隐私这个方面来说,问题的根源在于比特币交易是公开的。所以如果您始终使用相同的地址,那别人就可以看到您拥有的资产和收到的资产,以及时间戳,并以此推断出您的相关信息。斯诺登的事件的披露,打开了许多人头上的“默认隐私”灯。这不是件坏事,因为这样做有助于防范类似的隐私安全事件。

在上一篇文章中我们探讨了一种解决方案叫HD Wallet,这挺有用的,但是如果你的根公钥和用于派生子密钥的ID一起泄漏的话,您的信息将会被暴露。因此为了防止此类问题的发生,我们将探讨下加密地址。

下面我将介绍如何使用密码来加密您的私钥,我们称这些加密后的私钥为加密密钥。而且,就像前面篇文章中的HD Wallet一样,它将能够授权第三方为您生成加密密钥,而无需向他提供相关密码信息和底层私钥。如果这个第三方是你用来支付的网站,这意味着如果它被黑了,黑客也是徒劳无功的,因为他不会得到你的私钥访问权限授权。(但是你的个人和财产安全将可能处于一个较弱的级别)

私钥加密:两个方面(BIP 38)

有两种办法来生成一个加密密钥:

  • 通过私钥
  • 通过PassphraseCode (当您需要将流程委托给不受信任的第三方时这会很有用)

通过您的私钥进行加密

试想下,你通过一个比特币私钥来回收你的资金。通常情况下,拥有私钥的人就可以花费你的资金,这是基本的原理。但是你可以用密码来加密它,所以这时别人就需要同时知道你的私钥和密码才能花你的钱了。

代码实现:

Key key = new Key(); //创建一个新的私钥
BitcoinSecret secret = key.GetBitcoinSecret(Network.Main);
Console.WriteLine(secret); //用base58的检查格式输出私钥
BitcoinEncryptedSecret encrypted = secret.Encrypt("This is my secret password");
Console.WriteLine(encrypted); //用base58的检查格式输出加密后的私钥
key = encrypted.GetKey("This is my secret password"); //获得前面的私钥

加密流程的原理基于BIP 38。它使用的密钥派生算法Scrypt能抵御暴力破解,从而遏制恶意行为。

通过PassphraseCode进行加密

在某些情况下,您希望允许第三方(例如支付服务器)为您生成比特币地址和相关的加密密钥 ......但是您又不想提供私钥或密码

在这种情况下,您可以向第三方提供PassphraseCode,然后第三方将为您生成密钥。(例如应用到每一笔商业交易中)

代码实现:

BitcoinPassphraseCode result = new BitcoinPassphraseCode("This is my secret password", Network.Main, null); //Generate a passphrase, even if the password is used in the constructor, it is not embedded in the PassphraseCode
Console.WriteLine(result); //用base58的检查格式输出passphraseCode
//发送passphrase给第三方
var generationResult = result.GenerateEncryptedSecret(); //生成一个新加密密钥
Console.WriteLine(generationResult.GeneratedAddress); //输出生成的地址
Console.WriteLine(generationResult.EncryptedKey); //输出生成的地址比特币加密密钥
            
//返回生成的地址给使用者
Key key = generationResult.EncryptedKey.GetKey("This is my secret password");

您唯一提供给第三方的信息就只有比特币PassphraseCode,它不包含任何敏感数据。第三方可以使用它为您生成加密密钥,但无法解密它们。

保护您的隐私:加密地址

如果你想要个简单的,静态的且固定的比特币地址,还要能兼顾比特币PassphraseCode或HD 密钥的保护隐私的优点,那么加密地址就是你所需要的。

这是加密地址背后的最初想法:

作为收款方,你将公布一个消费公钥,同时你得注意不要泄露了对应的消费私钥了。

作为付款方,您可以把公布的消费公钥与一个临时密钥组合在一起,这个临时密钥是随机的,临时的。然后生成加密公钥和你用来付款的比特币地址

作为收款方,您将收到临时密钥,将消费公钥和付款方的临时密钥结合就能算出加密公钥这样你就可以用加密公钥来消费前面付款方生成的比特币地址中的资金了。

但是,这样的设计存在一个基本问题。临时密钥无法自动从付款方发送到收款方。

解决的办法是在将资金发送到对应的比特币地址时,将临时密钥也一起打包到这笔交易中。在交易中,将生成两个TxOut:一个是向比特币地址的支付数据(消费TxOut),另一个是嵌入了临时密钥的不可消费TxOut。我们称这种不可消费的TxOut加密元数据。我把这一对TXOUT的组合称作加密交易

作为收款方,您可以在比特币网络上扫描所有这种加密交易,然后提取交易中的临时密钥,然后(和你的消费公钥组合)算出加密公钥并检查其对应的比特币地址是否和交易中的消费TxOut中的比特币地址相匹配。

作为收款方,您可能希望自动执行此类扫描,但是,您应该不会想把消费私钥交给扫描软件,因为扫描软件或黑客可以使用它来窃取您的金钱。

解决方案是引入扫描密钥扫描软件付款方用它来生成或扫描加密公钥。这样,扫描软件不需要你的消费私钥也能够扫描区块链来汇报你的余额。但是,现在付款方需要两条信息才能够向你付款:扫描密钥 + 消费公钥,这两个是捆绑在公开共享的比特币加密地址中的

现在,付款方想要支付你一些钱,下面是他生成加密公钥的流程。(请注意,现在需要的两个密钥是来自加密地址中的)

作为收款人扫描软件,将不再需要消费私钥来检查一笔交易是否是支付给你的。

当你想花钱的时候,就可以使用消费公钥来手动获取加密公钥

这种交易模式是DarkWallet目前使用的,下面的代码使用了NBitcoin库来实现这种模式。

Key scan = new Key();
Key spend = new Key();
BitcoinStealthAddress address = spend.PukKey.CreateStealthAddress(scan.PubKey,Network.Main);
//收款方在论坛或其他地方公布地址
//付款方创建交易
Key ephem = new Key(); //如果没有指定的话就创建一笔支付
StealthPayment payment = address.CreatePayment(ephem);
//把支付添加到交易中
Transaction tx = new Transaction();
payment.AddToTransaction(tx);
//收款方通过区块链接受支付(address.Bitfield.GetPayments(tx))
Key key = spend.Uncover(scan,payment.Metadata.EphemKey);
//或者你想要用公钥(equals to key.PubKey)
PubKey pubkey = spend.PubKey.UncoverReceiver(scan, payment.Metadata.EphemKey);

您可以使用sx(Linux上的命令行实用程序)跟着来复现这些步骤,验证这种做法是否可行。

这里有一个成功可行的的单元测试链接

结论

本文试图保持对开发者友好。我把数学原理文档放在下面的链接中了。对我来说我很难理解链接中的总体流程,因为我对数学原理(椭圆曲线)不是很熟悉,我希望这篇文章能够帮助其他开发人员理解其中的大意,而不用被数学搞得头昏脑胀。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 通过您的私钥进行加密
  • 通过PassphraseCode进行加密
  • 保护您的隐私:加密地址
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档