essay on programming languages, computer science, information techonlogies and all.

Wednesday, June 6, 2018

Cryptography tutorial using Poco

Poco has crypto module and here is a tutorial of cryptography using Poco. Symmetric encryption is encrypt and decrypt using a key known by two player. Simple but hard to make key to be safe.

#include "Poco/Crypto/Cipher.h"
#include "Poco/Crypto/CipherKey.h"
#include "Poco/Crypto/CipherFactory.h"

auto& factory = CipherFactory::defaultFactory();
string transmission;

{
  Cipher* alice = factory.createCipher( CipherKey( 
    "aes-256-ecb", "open sesame"));
  transmission = alice->encryptString( 
    "Tall tree, Spy-glass shoulder, ... Skeleton Island ESE and by E");
}

{
  Cipher* bob = factory.createCipher( CipherKey( 
    "aes-256-ecb", "open sesame"));
  string decrypted = bob->decryptString(transmission);
  assert(decrypted == 
    "Tall tree, Spy-glass shoulder, ... Skeleton Island ESE and by E");
}
To remove this unsafe key, asymmetric encryption can be used. To do it, first priavate and public key should be generated. OpenSSL can be used like below.


>openssl.exe genrsa -des3 -out private_bob.pem 2048
Generating RSA private key, 2048 bit long modulus
...................+++
.................................................................+++
unable to write 'random state'
e is 65537 (0x10001)
Enter pass phrase for private_bob.pem:
Verifying - Enter pass phrase for private_bob.pem:


>openssl.exe rsa -in private_bob.pem -outform PEM -pubout -out public_bob.pem
Enter pass phrase for private_bob.pem:
writing RSA key

Then Alice can encode message using Bob's public key. Then only Bob can decode it using his private key.

#include "Poco/Crypto/RSAKey.h"
#include "Poco/Crypto/RSADigestEngine.h“

auto& factory = CipherFactory::defaultFactory();
string transmission;

{
  Cipher* alice = factory.createCipher(RSAKey( "public_bob.pem"));
  transmission = alice->encryptString(
    "Tall tree, Spy-glass shoulder, ... Skeleton Island ESE and by E");
}

{
  Cipher* bob = factory.createCipher(RSAKey( "", "private_bob.pem", "bobbob"));
  string decrypted = bob->decryptString(transmission);
  assert(decrypted == "Tall tree, Spy-glass shoulder, ... Skeleton Island ESE and by E");
}
The assymetric encryption can be extended to make contract between two players which is called digital signature.
Here, Alice can verify Bob's digital signature with the contract he promised.

// Poco::DigestEngine::Digest is std::vector 
tuple transmission;

{
  string contract = 
    "Alice will give Bob $100 and Bob will give Alice two magic mushrooms";
  RSADigestEngine bob(RSAKey("", "private_bob.pem", "bobbob"));
  bob.update(contract);
  transmission = make_tuple(contract, bob.signature());
}

{
  RSADigestEngine alice(RSAKey("public_bob.pem"));
  alice.update(get<0>(transmission));
  bool isValid = alice.verify(get<1>(transmission));
  assert(isValid == true);
}

Imagine, Alice get greedy and forged the contract, then Bob's signature doesn't work anymore.

// Poco::DigestEngine::Digest is std::vector 
tuple transmission;

{
  string contract = 
    "Alice will give Bob $100 and Bob will give Alice two magic mushrooms";
  RSADigestEngine bob(RSAKey("", "private_bob.pem", "bobbob"));
  bob.update(contract);
  transmission = make_tuple(contract, bob.signature());
}

{
  RSADigestEngine alice(RSAKey("public_bob.pem"));
  alice.update(
    "Alice will give Bob $100 and Bob will give Alice three magic mushrooms");
  bool isValid = alice.verify(get<1>(transmission));
  assert(isValid == false);
}
This digital signature can be extended further to digital coin. First chained transaction should be established. Here is a diagram from Satoshi Nakamoto's paper which shows the concept.

Here, Queen generate coin and give it to Alice; Queen use Alice's public key to generate transaction hash and sign the hash using majesty private key.

struct Transaction
{
  string Hash;
  vector Signature;
};

Transaction queenToAlice;
{
  // Queen
  RSAKey alicePublic("public_alice.pem");
  stringstream alicePublickey;
  alicePublic.save(&alicePublickey);

  Crypto::DigestEngine hasher("SHA256");
  hasher.update("Queen's own right to create coin");
  hasher.update(alicePublickey.str());
  string hash = Crypto::DigestEngine::digestToHex(
  hasher.digest());

  RSADigestEngine queen(RSAKey("", "private_queen.pem", "queenqueen"));
  queen.update(hash);

  queenToAlice = Transaction{ hash, queen.signature() };
}
Now, Alice can verify Queen's benevolence using Queen's public key.

{
  // Alice
  RSADigestEngine alice(RSAKey("public_queen.pem"));
  alice.update( queenToAlice.Hash );
  assert( true == alice.verify(queenToAlice.Signature));
}
Then Alice send the coin to Bob; Update the transaction 's hash with Bob's public key and sign it with Alice's private key.

Transaction aliceToBob;
{
  // Alice
  RSAKey bobPublic("public_bob.pem");
  stringstream bobPublickey;
  bobPublic.save(&bobPublickey);

  Crypto::DigestEngine hasher("SHA256");
  hasher.update(queenToAlice.Hash);
  hasher.update(queenToAlice.Signature.data(), 
  queenToAlice.Signature.size());
  hasher.update(bobPublickey.str());
  string hash = Crypto::DigestEngine::digestToHex(
  hasher.digest());

  RSADigestEngine alice(RSAKey("", 
    "private_alice.pem", "alicealice"));
  alice.update(hash);

  aliceToBob = Transaction{ hash, alice.signature() };
}
And Bob can verfiy Alice's coin given to himself.

{
  // Bob
  RSADigestEngine bob(RSAKey("public_alice.pem"));
  bob.update(aliceToBob.Hash);
  assert(true == bob.verify(aliceToBob.Signature));
}
The genuine idea of Bitcoin is BlockChain which verify the transaction in decentralized way. Here is another excerpt from the paper.
It says there should be proof-of-work ; which is basically finding a additional string - nounce - that make hash to start with number of '0' characters. Finding nounce is hard but verifying it is easy. Here is how to verify nounce.

struct Transaction {  string Hash, Signature; };

struct Block {
  string PrevHash, Nounce;
  vector Transactions;
};

Block t0 = {
  "Hello, world!", "4250",  { Transaction{ "", "" } }
};


// verfiy t0 block's transactions and proof-of-work
hasher.update(t0.PrevHash);
for (auto tx : t0.Transactions) {
  hasher.update(tx.Hash); hasher.update(tx.Signature);
}
hasher.update(t0.Nounce);

t1.PrevHash = Crypto::DigestEngine::digestToHex(hasher.digest());
assert(t1.PrevHash.substr(0, 4) == "0000");
Here is a way to finding nounce by brute-force.

// gather transactions
t1.Transactions = { 
  Transaction{ "ab", "cd" }, 
  Transaction{ "12", "34" }, 
  Transaction{ "56", "78" } };

// race for the nounce
for (int nounce = 0;; ++nounce)
{
  hasher.reset();
  hasher.update(t1.PrevHash);
  for (auto tx : t1.Transactions) {
    hasher.update(tx.Hash); hasher.update(tx.Signature);
  }
  hasher.update(to_string(nounce));

  string hash = Crypto::DigestEngine::digestToHex(hasher.digest());
  if (hash.substr(0, 4) == "0000") {
    t1.Nounce = to_string(nounce);
    break;
  }
}

// broadcast t1 block to world 

2 comments:

Sowmya said...
This comment has been removed by a blog administrator.
Akanshya said...
This comment has been removed by a blog administrator.