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)
:EndNamespaceThe 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
∇
:EndClassLet'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 midnightAny 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)
∇
:EndClassNow, 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
32She 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.
APL Wiki