Wolfram Computation Meets Knowledge

Two Lines of Code to Bulletproof Encryption: Advancements in Cryptography Development in the Wolfram Language

Two Lines of Code to Bulletproof Encryption: Advancements in Cryptography Development in the Wolfram Language

Cryptography functionality in the Wolfram Language has been growing significantly ever since it was originally released in Version 10.1. In the latest release, we added support for generation and verification of digital signatures for expressions, files and cloud objects; you can encrypt or digitally sign anything—from simple messages to images or code. In order to maintain our users’ security and safety, we base our algorithms on OpenSSL libraries. While OpenSSL normally requires a great deal of experience to use, integration with the Wolfram Language has made it simple.

Encryption

In the Wolfram Language, encrypting information is as easy as it could possibly be. When using Encrypt to protect data of any sort, you’ll enter a password in an AuthenticationDialog window to securely protect your data:

model = ExampleData[{"Geometry3D", "SpaceShuttle"}];
&#10005

model = ExampleData[{"Geometry3D", "SpaceShuttle"}];

enc = Encrypt
&#10005

enc = Encrypt[AuthenticationDialog["Password", #Password &], model]

Authentication

That’s the entire encryption process from start to finish. With just two lines of Wolfram Language code, your data is secured with a bulletproof key derived from your password and industry-standard ciphers.

Decrypt will return your initial data, exactly as it was:

Decrypt
&#10005

Decrypt[AuthenticationDialog["Password", #Password &], enc]

Using OpenSSL from any other programming language is exponentially more complicated. In order to perform the same simple yet secure encryption process in your C/C++ program with OpenSSL, you would need to read through time-consuming documentation. Python and R do not natively run OpenSSL at all—you’d need to select and configure a third-party cryptography package and install OpenSSL separately.

Blockchain Security

Elliptic curve keys and digital signatures, newly supported in Version 12.1, allow Wolfram Language users to work extensively with blockchains. We currently support secp256k1, the same elliptic curve used by Bitcoin, Ethereum, ARK and a myriad of other blockchains. In future versions of the Wolfram Language, we plan to support other standard curves, such as those recommended by the NIST.

Generate elliptic curve–based private and public keys using GenerateAsymmetricKeyPair:

keys = GenerateAsymmetricKeyPair
&#10005

keys = GenerateAsymmetricKeyPair["EllipticCurve"]

Once the keys are generated, they are used to create and verify digital signatures:

message = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
&#10005

message = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";

signature = GenerateDigitalSignature
&#10005

signature = GenerateDigitalSignature[message, keys["PrivateKey"]]

VerifyDigitalSignature
&#10005

VerifyDigitalSignature[{message, signature}, keys["PublicKey"]]

The example message used here comes from block 0 of the Bitcoin blockchain. Adding support for elliptic curve digital signatures serves well for writing to blockchains. For instance, BlockchainTransactionSign uses them internally to sign a transaction before it’s ready to submit to a specified blockchain:

arkTX = BlockchainTransaction
&#10005

arkTX = BlockchainTransaction[<|
   
   "BlockchainBase" -> {"ARK", "Devnet"}, 
   "Recipient" -> "DLesojAmpcA4jQbJDz5JKQ73k1RervJwfi", 
   "Fee" -> 500000,
   "Amount" -> 5000000, "TransactionCount" -> 1|>]

BlockchainTransactionSign
&#10005

BlockchainTransactionSign[arkTX, 
 PrivateKey[
  Association["Type" -> "EllipticCurve", "CurveName" -> "secp256k1", 
   "PublicCurvePoint" -> 
{104531630294965477234702932341314658269653137311559363531300075335186\
469390907, 
     10640048778270064292136312118618106290978266224313779661960878181\
1804637106603}, 
   "PrivateMultiplier" -> 
    462334184832703249382743573975806080334034824670864224636440700338\
84386623284, "Compressed" -> True, 
   "PublicByteArray" -> 
    ByteArray[{3, 231, 26, 206, 92, 80, 143, 224, 194, 24, 207, 131, 
      164, 219, 131, 21, 1, 243, 142, 42, 166, 89, 103, 207, 196, 217,
       90, 115, 24, 134, 168, 138, 59}], 
   "PrivateByteArray" -> 
    ByteArray[{102, 55, 48, 2, 13, 244, 228, 151, 216, 47, 103, 217, 
      53, 81, 190, 188, 237, 119, 237, 194, 2, 245, 72, 113, 217, 50, 
      144, 69, 50, 10, 255, 52}]]]]

You can also use digital signatures to sign and verify images or any arbitrary Wolfram Language expression:

GenerateDigitalSignature
&#10005

GenerateDigitalSignature[\!\(
\*SubsuperscriptBox[\(\[Integral]\), \(0\), \(\[Infinity]\)]\(Log[
    x]\ Exp[\(-
\*SuperscriptBox[\(x\), \(2\)]\)] \[DifferentialD]x\)\), PrivateKey[
Association[
  "Type" -> "EllipticCurve", "CurveName" -> "secp256k1", 
   "PublicCurvePoint" -> {
    104531630294965477234702932341314658269653137311559363531300075335\
186469390907, 
     10640048778270064292136312118618106290978266224313779661960878181\
1804637106603}, 
   "PrivateMultiplier" -> 46233418483270324938274357397580608033403482\
467086422463644070033884386623284, "Compressed" -> True, 
   "PublicByteArray" -> ByteArray[{3, 231, 26, 206, 92, 80, 143, 224, 
     194, 24, 207, 131, 164, 219, 131, 21, 1, 243, 142, 42, 166, 89, 
     103, 207, 196, 217, 90, 115, 24, 134, 168, 138, 59}], 
   "PrivateByteArray" -> ByteArray[{102, 55, 48, 2, 13, 244, 228, 151,
      216, 47, 103, 217, 53, 81, 190, 188, 237, 119, 237, 194, 2, 245,
      72, 113, 217, 50, 144, 69, 50, 10, 255, 52}]]]]

“Know Your Keys”

We’ve greatly expanded user flexibility and freedom with public and private key objects. In Version 12.1, PrivateKey and PublicKey can compute all of the necessary parts of a key from an arbitrary value.

Access the public key of any blockchain transaction sender on Bitcoin, Ethereum or ARK:

BlockchainTransactionData
&#10005

BlockchainTransactionData[
"a93bfdff6679bc38cfdcd16cc38e34513fa2ee97186864e22cac5723864cde13", 
"SenderPublicKey", BlockchainBase -> "Ethereum"]

Use your own keys generated outside of the Wolfram ecosystem by pasting the necessary value (e.g. as a hex string). PrivateKey and PublicKey will do the rest of the work:

private = PrivateKey
&#10005

private = 
 PrivateKey[<|"Type" -> "EllipticCurve", 
   "PrivateHexString" -> 
    "E9873D79C6D87DC0FB6A5778633389F4453213303DA61F20BD67FC233AA33262"|>]

public = PublicKey
&#10005

public = PublicKey[private]

To experiment with the mathematical properties of private and public keys, you could specify an arbitrary value:

PrivateKey
&#10005

PrivateKey[<|"Type" -> "EllipticCurve", "PrivateMultiplier" -> 100|>]

Always be careful when inventing your own private keys. If you need one for practical use, it’s better to generate a pair using built-in, cryptographically secure random number generation with GenerateAsymmetricKeyPair.

Generally speaking, humans struggle to create long, random and strong passwords—usually opting for short passwords that are easier to reuse, making them vulnerable and easier to hack. GenerateDerivedKey, a key derivation function (used in password hashing and authentication), strengthens the key:

GenerateDerivedKey
&#10005

GenerateDerivedKey["password"]

Working with Files

We’ve created EncryptFile to keep sensitive data private and only accessible by those who are authorized to do so. This enables research, computed results, Wolfram Language code or any other sensitive information to be encrypted and stored safely.

Encrypt a file containing an image, writing the result to a new file:

EncryptFile
&#10005

EncryptFile[AuthenticationDialog["Password", #Password &], 
 FindFile["ExampleData/rose.gif"], "codedrose.mx"]

Use DecryptFile to get the encrypted file back, again putting the result in a new file:

DecryptFile
&#10005

DecryptFile[
 AuthenticationDialog[
  "Password", #Password &], "codedrose.mx", "rose.gif"]

Import the decrypted file:

Import
&#10005

Import["rose.gif"]

Additionally, we’ve added GenerateFileSignature and VerifyFileSignature for digitally signing and verifying files of any format (even cloud objects!). Both functions use the security of RSA or elliptic curves:

object = CloudPut
&#10005

object = CloudPut[123, "test"];

keys = GenerateAsymmetricKeyPair
&#10005

keys = GenerateAsymmetricKeyPair["RSA"];

signature = GenerateFileSignature
&#10005

signature = GenerateFileSignature[object, keys["PrivateKey"]]

VerifyFileSignature
&#10005

VerifyFileSignature[{object, signature}, keys["PublicKey"]]

There’s Always More

Get more out of cryptography in the Wolfram Language from our Documentation Center or by watching a livestream in which I explain the latest features in more detail. We are constantly expanding and improving upon cryptography functionality for future versions. If you have ideas on what we should prioritize for this feature, let us know in the comments.


This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. This product includes cryptographic software written by Eric Young.

Get full access to the latest Wolfram Language functionality with a Mathematica 12.1 or Wolfram|One trial.

Comments

Join the discussion

!Please enter your comment (at least 5 characters).

!Please enter your name.

!Please enter a valid email address.

3 comments

  1. I would like Mathematica support different curves for elliptic curve cryptography.

    Does GenerateAsymmetricKeyPair and Generate/VerifyDigitalSignature use OpenSSL?
    How if I have not installed it?

    Reply
    • Thank you for your comment, Diego!
      We are planning to support more common elliptic curves in the next releases – such as SEC and NIST recommended ones. And you’re correct, GenerateAsymmetricKeyPair and Generate/VerifyDigitalSignature, as well as Encrypt and other Cryptography functions use OpenSSL under the hood!

      Reply
  2. It would be nice to take an existing private-key (assuming its compliment public-key (is not kept by the user) and insert it as an element/argument into the GenerateAsymmetricKeyPair[] function, such that the original Public Key can be derived. Ideally, this would produce the original public/private-key paired object once again.
    Currently, I have to use PublicKey[itsPrivateKey] to do this (which results in a single public key object seperate from the private one). Also, note that depending on the original Type that was specified inside GenerateAsymmetricKeyPair, like “Bitcoin”, the subsequent PublicKey[itsPrivateKey] approach does not always give you the original Public Key (when compared to the original paired object). Apparently, the result of PublicKey[itsPrivateKey] function can result in a public-key whos properties are in a different order than the original public-key. I believe this inconsistent ordering of properties is responsible for the non-identical square-icon graphic representations between the original public-key (in the paired object) and the single, derived, public key (same values..different order, leading to different square graphic icons).

    Reply