9

I have the following text string:

This is a test message.

  • Using my bitcoin public key (bitcoin address?), how can I encrypt this message?

  • How would I decrypt the message using a bitcoin private key?

  • 1
    Do you want to encrypt to a public key, or using a password? Those two require very different technologies. – Pieter Wuille Nov 2 '18 at 19:30
  • 2
    basically take anyone's bitcoin address and encrypt a message, then send this person the encrypted message where he can decrypt with his bitcoin private key. Or that doesn't work at all? – Patoshi パトシ Nov 2 '18 at 19:37
  • But you're also mentioning AES and needing a password to decrypt? – Pieter Wuille Nov 2 '18 at 19:44
  • 1
    updated question. removed aes reference. was confusing. – Patoshi パトシ Nov 2 '18 at 19:45
  • 1
    Bitcoin address is derived from publickey but is not sufficient to encrypt. – dave_thompson_085 Nov 3 '18 at 0:05
19

Yes, this is possible.

However, I want to upfront state that this is not advisable for multiple reasons:

  • Bitcoin keys are intended to be single use for privacy reasons, and leveraging them for encryption unnecessarily encourages treating them as a long-lived identity.
  • There may be ugly and dangerous interactions when keys are used for multiple protocols independently.
  • You're much better off using systems that were actually designed for encryption than trying to piggy-back off Bitcoin's cryptography.
  • Implementing your own cryptography is very dangerous (in general, unless you know what you're doing, and get plenty of review from experts).

A scheme called ECIES exists that lets you leverage elliptic curve keys to create an encryption system.

In short, it works by:

The sender:

  • generates an ephemeral private key k using a strong cryptographic random number generator, with associated public key k = kG (multiplication refers to Elliptic Curve multiplication here).
  • computes an ECDH shared secret s = H(kP), where P is the public key of the recipient.
  • computes two symmetric keys x1 and x2 using a KDF seeded by s: (x1, x2) = KDF(s).
  • encrypts the message m using AES, with x1 as the key, to obtain c = AECEncx1(m).
  • compute a MAC on K and c with x2 as key: h = MACx2(K || c).
  • sends (K, c, h) to the recipient.

The recipient:

  • computes the ECDH shared secret, using s = H(pK), where p is his private key.
  • computes the same two symmetric keys x1 and x2: (x1, x2) = KDF(s).
  • computes the same MAC h' = MACx2(K || c)
  • verifies that h' = h, and fails if not.
  • decrypts the message using s, m' = AESDecx1(c).
  • 4
    If you don't have a MAC then what you've implemented is not ECIES and would often be vulnerable to decryption oracle attacks. E.g. I take a message,to you I want to decrypt and then send a series of messages to you reusing the ephemeral key and probing how you respond to different junk ciphertexts. – G. Maxwell Nov 3 '18 at 2:43
  • @G.Maxwell Good point, fixed. – Pieter Wuille Nov 3 '18 at 2:53
  • couple of typos: with associated public key k = kG .. here it should be capital K = kG; and AECEnc should be AESEnc – Wapac Nov 30 '18 at 11:10
5

If you want to encrypt messages, you should use a proper message/file encryption tool like PGP/GPG. Homebrewed cryptography using bitcoin things is prone to having poor security properties.

  • 1
    While you're probably right. This doesn't really seem to answer the question. I would think you're saying "it can't be done", but then again it seems you're saying it can be done, but are not answering "how", which is the question. – JoL Nov 3 '18 at 0:44
  • 1
    The answer is "you probably shouldn't". I think this is a much more valuable answer than giving a tutorial that ultimately leaves the asker less informed and potentially completely insecure. – G. Maxwell Nov 3 '18 at 1:09
  • 2
    I disagree "you probably shouldn't" is an answer at all. It could be part of an answer, as a disclaimer like in Pieter's answer. Alone, however, is more like denying an answer. Though questions at times ask things that seem like no one should need, there could be rare legitimate use-cases. Even if the OP's need isn't legitimate, a future reader's might. – JoL Nov 3 '18 at 2:54
3

Be sure to follow the warnings given previously in other answers, but for the record this was implemented in a project called Bitmessage. The main implementation is in Python at https://github.com/Bitmessage/PyBitmessage. There is also an npm module for node.js that implemented this for the server and browser using openssl c libraries under the hood: eccrypto:

Install dependencies

$ npm install -g eccrypto

index.js

var crypto = require("crypto");
var eccrypto = require("eccrypto");

var privateKeyA = crypto.randomBytes(32);
var publicKeyA = eccrypto.getPublic(privateKeyA);
var privateKeyB = crypto.randomBytes(32);
var publicKeyB = eccrypto.getPublic(privateKeyB);

// Encrypting the message for B.
eccrypto.encrypt(publicKeyB, Buffer("msg to b")).then(function(encrypted) {
  // B decrypting the message.
  eccrypto.decrypt(privateKeyB, encrypted).then(function(plaintext) {
    console.log("Message to part B:", plaintext.toString());
  });
});

// Encrypting the message for A.
eccrypto.encrypt(publicKeyA, Buffer("msg to a")).then(function(encrypted) {
  // A decrypting the message.
  eccrypto.decrypt(privateKeyA, encrypted).then(function(plaintext) {
    console.log("Message to part A:", plaintext.toString());
  });
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.