专栏首页代码乱弹NBitcoin:密码学第2部分

NBitcoin:密码学第2部分

介绍

我第一篇关于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 条评论
登录 后参与评论

相关文章

  • 比特币钱包开发【C#】 原

    在这个教程中,们将使用C#来开发一个比特币钱包,我们使用NBitcoin这个库。教程中的代码实现了比特币的存储、接收和支付功能,可以很容易地移植到其他应用中。

    用户1408045
  • HBitcoin:C#高级比特币钱包库 - 保护您的财产安全

    在几年前,我有写一个叫HiddenBitcoin的钱包库,那是我第一次接触跟比特币相关的项目。多年来我一直在复用这个项目中的代码并不停的改进优化它,虽然到...

    飞翔的猪脚粉
  • 用NBitcoin进行区块链开发(5)

    BTC的区块链(blockchain)存储着许多交易(transaction),transaction简单来讲是指BTC从某个地址到某个地址的转移记录。与我们平...

    申龙斌
  • 用NBitcoin进行区块链开发(5)

    BTC的区块链(blockchain)存储着许多交易(transaction),transaction简单来讲是指BTC从某个地址到某个地址的转移记录。与我们平...

    申龙斌
  • NBitcoin:最完整的比特币港口(第1部分:加密)

    Codeproject的研究员们,我很高兴发布系列的第一篇文章。[NEW:第2部分在这里 ]我最近从C++到C#移植了一部分很棒的比特币源代码。我导入了几乎所有...

    teachertian
  • 用NBitcoin进行区块链开发(7):助记词

    比特币的私钥是256位的二进制数字,占32个字节,比如: 3243F6A8885A308D313198A2E03707344A4093822299F31D008...

    申龙斌
  • 第1章:监督学习和朴素贝叶斯分类 - 第2部分(编码)

    注意:如果你没有经历过朴素贝叶斯理论的第一部分,我建议你仔细阅读。(4 分钟阅读)这里。

    iOSDevLog
  • 用NBitcoin进行区块链开发(6):交易签名

    比特币交易的签名过程是所有环节中最复杂的步骤之一,下面两篇文章对这个过程有详细的描述。

    申龙斌
  • Dan Boneh密码学笔记2

    实际上我的学习时间得在四个小时才够,而且得是脑子清醒的四个小时。这还是刚开始简单的流密码......感觉也就听懂了90%,真正消化完......尤其那些安全性的...

    安包
  • 第九届BIU密码学冬令营2 Zero-Knowledge for NP

    1. Alon Rosen: Introduction to Zero Knowledge

    安包
  • iOS逆向(2)-密码学(Hash&对称加密)

    原文地址:https://juejin.im/post/5c7e72cd6fb9a049fc044519”

    iOSSir
  • CTF---密码学入门第六题 古典密码

    古典密码分值:10 来源: 北邮天枢战队 难度:易 参与人数:5115人 Get Flag:1549人 答题人数:1783人 解题通过率:87% 密文内容如...

    Angel_Kitty
  • InnoDB数据锁–第2部分“锁”

    在InnoDB Data Locking –第1部分“简介”中,我们通过同时编辑电子表格的比喻描述了锁能够解决的难题。虽然通过比喻可以获得直观的感觉,但是我们需...

    MySQLSE
  • 周志华《机器学习》第2章部分笔记

    ①误差(error):学习器的预测输出与样本的真实输出之间的差异 ②训练误差(training error)或经验误差(empirical error):在训练...

    Natalia_ljq
  • 斯坦福大学密码学-分组密码 03

    典型的分组密码以迭代的形式构建。输入密钥k,然后将密钥扩张成一系列的回合密钥 到 。使用这些回合密钥一次又一次的迭代使用回合函数加密明文信息。

    静怡
  • [译] 调试 RxJS 第2部分: 日志篇

    用户1687375
  • 斯坦福大学密码学-使用分组密码 04

    可以设计出攻击者A,询问 x=0和 x=1,因为PRP中没有f(0)=f(1)的情况,所以当f(0)=f(1)时,一定是实验1,所以输出1,否则,输出0。所以实...

    静怡
  • 大数据篇---Impala学习第 1 部分 Impala概述第 2 部分 Impala 安装与⼊⻔案例第 3 部分 Imapla的架构原理第 4 部分 Impala的使用

    invalidate metadata全量刷新,性能消耗较⼤,主要⽤于hive当中新建数据库或者数据库表的时候来进 ⾏刷新。

    用户2337871
  • Django来敲门~第一部分【2. 安装】

    安装完成后,我们需要验证安装是否成功,可以执行如下命令,通过查看安装的django版本信息来验证

    大牧莫邪

扫码关注云+社区

领取腾讯云代金券