Cryptography with .Net
Contents
Overview
This page contains examples of the most common crypting tasks. It is probably the easiest way to find out about how to use Cryptography with .Net.
For a complete reference see Wikipedia.
Math
The mathematics involved in cryptography are not difficult to grasp. It is the implementation which is more difficult, specially with languages that don't offer extended precision arithmetic.
.Net offers a series of classes to handle cryptography. They reside in System.Security.Cryptography which is in System.Core.dll
APL Code
Here is a namespace containing a few utilities and a HASH function:
Hash funtion
:Namespace CryptoTools ∇ r←DNetCrypto ⍝ This is the location of the cryptography libraries r←'System.Security.Cryptography,\Program Files' ⍝ change for 64b OS r,←'\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll' ∇ ∇ value←hash string;str;⎕USING ⍝ Return hash value of the string given as arg :If isChar str←,string str←⎕UCS str ⍝ turn characters into numbers for the hash fn {}⎕DR str ⍝ kludge for V12 to ensure str is small int :EndIf ⎕USING←DNetCrypto value←(⎕NEW SHA256Managed).ComputeHash⊂str ⍝ also SHA1/384/512, CRC32 & MD5CryptoServiceProvider ∇ if←/⍨ ⋄ UTF8←'UTF-8'∘⎕ucs ⋄ isChar←{∨/0 2=10|⎕DR 1/⍵} UCSN←{~isChar ⍵:⍵ ⋄ v{⍺}⎕dr v←UTF8 ⍵} ⍝ ⎕DR forces demotion (for V12) :EndNamespace
The hash function (here SHA256, but it could be another) can be applied to any string:
CryptoTools.hash ⊃,/⎕src CryptoTools 165 157 223 218 183 249 78 22…
Symmetric encryption
The following class will handle symmetric cryptography:
:Class CodeSymmetric :include CryptoTools M2MS←{8÷⍨⍵[2]+0,s×⍳(-/2↑⍵)÷1⌈s←¯1↑⍵} ⍝ valid Key sizes [min-max] ∇ boa provider;choices;msg;n :Access public :Implements constructor ⍝ Data Encryption Standard (DES) supports a 64 bit key only ⍝ Rivest Cipher 2 provider supports keys from 40 to 128* bits ⍝ Rijndael (also known as AES) provider supports keys 128/192/256* ⍝ TripleDES provider (also known as 3DES) supports keys of 128/192* choices←'DES' 'RC2' 'Rijndael' 'TripleDES' msg←'Invalid provider; choose one of',⍕choices msg ⎕SIGNAL 99 if(⍴choices)<n←choices⍳⊂provider ⎕USING←DNetCrypto choices←DESCryptoServiceProvider RC2CryptoServiceProvider _algo←⎕NEW n⊃choices,RijndaelManaged TripleDESCryptoServiceProvider n←⊃_algo.LegalKeySizes.(MaxSize MinSize SkipSize) _vks←M2MS n ⍝ all valid Key sizes IV←'1Az=-@qT' ⍝ Initialisation Vector ⎕DF provider ⍝ conveniently identify instance ∇ ∇ r←RandomKey ⍝ This generates a random Key :Access public _algo.GenerateKey r←_algo.Key ∇ :property Key ⍝ The key used to encrypt/decrypt data :access public ∇ r←get r←_key ∇ ∇ set val;val;msg;t msg←'⍴Key must be ',((1<⍴t)/'one of '),⍕t←_vks msg ⎕SIGNAL 11 if ~(⍴val←val.NewValue)∊t _algo.Key←_key←UCSN val ∇ :endproperty ⍝ Using the default Cipher Block Chaining (CBC) mode, all data blocks ⍝ are processed using the value derived from the previous block; the ⍝ first data block has no previous data block to use, so it needs an ⍝ Initialisation Vector (IV) to feed the first block :property IV :access public ∇ r←get r←_iv ∇ ∇ set Value;val;validBS ⍝ We must ensure the value fits requirements: validBS←M2MS⊃_algo.LegalBlockSizes.(MaxSize MinSize SkipSize) :If ~validBS∊⍨⍴val←Value.NewValue ⍝ if not a valid block size val←validBS[1++/validBS<⍴val]⍴val ⍝ pick the next one up :EndIf _algo.IV←_iv←UCSN val ∇ :endproperty ⍝ Encrypts the specified Data using preset key and preset IV ∇ r←EncryptString d;⎕USING;ms;cs;cr :Access public ⎕USING,⍨←⊂'System' ⍝ The key and IV have better been set ms←⎕NEW IO.MemoryStream cr←_algo.CreateEncryptor ⍬ cs←⎕NEW CryptoStream(ms cr CryptoStreamMode.Write) cs.Write((UCSN d)0,⍴d) cs.Close ms.Close r←ms.ToArray ∇ ⍝ Decrypts the specified data using preset key and preset IV ∇ r←DecryptCipher encryptedData;b;ms;cs;len;⎕USING :Access public ⎕USING,⍨←'System' 'Dyalog' ms←⎕NEW IO.MemoryStream(encryptedData 0,⍴encryptedData) cs←⎕NEW CryptoStream(ms(_algo.CreateDecryptor ⍬)CryptoStreamMode.Read) b←⎕NEW ByRef,⊂⊂3/⍨⍴encryptedData len←cs.Read(b 0,⍴encryptedData) cs.Close r←⎕UCS len↑b.Value ∇ :EndClass
Let's try it:
s1←⎕new CodeSymmetric 'TripleDES' s1.Key←16⍴'secret' +cs1←s1.EncryptString 'Let''s rendez-vous at midnight' 155 230 195 207 193 180 216 228 2 14 11… s1.DecryptCipher cs1 Let's rendez-vous at midnight
Any instance of the class will do to decrypt the cipher as long as the Initialisation Vector and the key are the same.
Obviously. that code could be modified to, say, accept the Initialisation Vector and/or the key at instantiation time, not to mention the handling of certificates, etc.
Asymmetric encryption
The following class will handle asymmetric cryptography:
:Class CodeAsymmetric ⍝ The only provider supported is the RSACryptoServiceProvider. :include CryptTools ⎕using← DNetCrypto ⋄ ⎕io ⎕ml←1 ⋄ ⎕wx←3 ∇ boa0 ⍝ The public Key is automatically generated :Implements constructor :Access public _rsa←⎕NEW RSACryptoServiceProvider GenerateNewKeys ∇ ∇ boa1 arg ⍝ This is where you make the public Key. ⍝ It could be made of INI files, XML, etc. ⍝ Here we only accept XML strings. :Implements constructor :Access public _rsa←⎕NEW RSACryptoServiceProvider _rsa.FromXmlString⊂arg ∇ ⍝ Generates a new public/private key pair as strings ∇ {(publicKeyXML privateKeyXML)}←GenerateNewKeys ⍝ Generate new keys for this instance :Access public publicKeyXML←_rsa.ToXmlString 0 privateKeyXML←_rsa.ToXmlString 1 ∇ ∇ r←Decrypt cipher :Access public r←UTF8 _rsa.Decrypt cipher 0 ∇ ∇ r←Encrypt d :Access public r←_rsa.Encrypt((UCSN d)0) ∇ :EndClass
Now, Adam creates an object with both public and private keys:
adam←⎕new CodeAsymmetric (pub pvt)← adam.GenerateNewKeys
Adam forwards the public key to Bea who uses it to send him messages:
bea←⎕new CodeAsymmetric pub +msg←bea.Encrypt 'meet me at midnight’ 89 12 181 136 53 …
Adam decrypts the message like this:
adam.Decrypt msg meet me at midnight
That’s how easy it is.
Because asymmetric cryptography is calculation intensive it is best to limit the material to small strings.
Now, in real life messages tend to be longer and symmetric cryptography works best. What some people do is to encrypt the large text symmetrically with a key which is encrypted asymmetrically. They often also add a signature, for example the hash of the message and/or encrypted key to ensure everything is kosher. Something along the lines of
beamsg←1000⍴'long message... ' code←⎕new CodeSymmetric 'RC2' code.Key←cpw←'secret' ⍴cryptedmsg←code.EncryptString beamsg 1008 ⍴cryptedkey←bea.Encrypt cpw 128 ⍴H←CryptoTools.hash cryptedkey,cryptedmsg 32
She then sends Adam the encrypted message, the encrypted key and the hash. Adam first checks there’s been no tampering:
H≡CryptoTools.hash cryptedkey,cryptedmsg 1
He then finds the key used to encrypt the message:
adam.Decrypt cryptedkey secret
Then he finally decodes the message:
decode←⎕new CodeSymmetric 'RC2' decode.Key←'secret' decode.DecryptCipher cryptedmsg long message... long message... long message...
That is the basis of message exchange protocols like SSL which will bundle up all the stuff to transfer, adding their own packaging information.
Links
There are all sorts of different links available. Wikipedia is a reliable source.
Vector also has been known to have articles on cryptography.
CategoryDotNet - CategoryDyalogDotNet - CategoryDyalogExamplesDotNet