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:
Engage with the code in this post by downloading the Wolfram Notebook
✕
model = ExampleData[{"Geometry3D", "SpaceShuttle"}]; |
✕
enc = Encrypt[AuthenticationDialog["Password", #Password &], model] |
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[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["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"; |
✕
signature = GenerateDigitalSignature[message, keys["PrivateKey"]] |
✕
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[<| "BlockchainBase" -> {"ARK", "Devnet"}, "Recipient" -> "DLesojAmpcA4jQbJDz5JKQ73k1RervJwfi", "Fee" -> 500000, "Amount" -> 5000000, "TransactionCount" -> 1|>] |
✕
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[\!\( \*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[ "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[<|"Type" -> "EllipticCurve", "PrivateHexString" -> "E9873D79C6D87DC0FB6A5778633389F4453213303DA61F20BD67FC233AA33262"|>] |
✕
public = PublicKey[private] |
To experiment with the mathematical properties of private and public keys, you could specify an arbitrary value:
✕
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["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[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[ AuthenticationDialog[ "Password", #Password &], "codedrose.mx", "rose.gif"] |
Import the decrypted file:
✕
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[123, "test"]; |
✕
keys = GenerateAsymmetricKeyPair["RSA"]; |
✕
signature = GenerateFileSignature[object, keys["PrivateKey"]] |
✕
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. |
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?
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!
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).