:Class Symmetric :field Private _DefaultIV ← '1Az=-@qT' :field Private readonly _BufferSize ← 2048 :field Private _key :field Private _iv :field Private _algo ⍝ Symmetric Algorithm :include CryptTools ⍝∇:Require =\crTools ⎕io ⎕ml←1 ⋄ ⎕wx←3 VKS←{8÷⍨⍵[2]+0,s×⍳(-/2↑⍵)÷1⌈s←¯1↑⍵} ⍝ valid Key sizes from max/min/skip ⍝ Instantiates a new symmetric encryption object using the specified ' ∇ boa1 method :Access public :Implements constructor New method 1 ∇ ∇ boa2(method uiv) :Access public :Implements constructor New method uiv ∇ ∇ New(provider useIV);choices;msg;n ⍝ The Data Encryption Standard provider supports a 64 bit key only ⍝ The Rivest Cipher 2 provider supports keys ranging from 40 to 128 bits, default is 128 bits ⍝ The Rijndael (also known as AES) provider supports keys of 128, 192, or 256 bits with a default of 256 bits ⍝ The TripleDES provider (also known as 3DES) supports keys of 128 or 192 bits with a default of 192 bits msg←'Invalid provider; choose one of',⍕choices←'DES' 'RC2' 'Rijndael' 'TripleDES' msg ⎕SIGNAL 99↓⍨(⍴choices)≥n←choices⍳⊂provider ⎕USING←DNetCrypto _algo←⎕NEW n⊃DESCryptoServiceProvider RC2CryptoServiceProvider RijndaelManaged TripleDESCryptoServiceProvider MMS←⊃_algo.LegalKeySizes.(MaxSize MinSize SkipSize) ⍝ Make sure key and IV are always set, no matter what Key←RandomKey :If useIV≡1 IV←_DefaultIV :ElseIf useIV≢0 '⍴IV must a multiple of 8'⎕SIGNAL 99 if 0≠8|⍴useIV←,useIV IV←_DefaultIV←useIV :Else IV←RandomIV :EndIf ∇ ∇ r←ValidKsizes r←VKS MMS ∇ ⍝ The key used to encrypt/decrypt data :property Key :access public ∇ r←get r←_key ∇ ∇ set Value;val;msg;t msg←'⍴Key must be ',((1<⍴t)/'one of '),⍕t←ValidKsizes msg ⎕SIGNAL 11 if~(⍴val←Value.NewValue)∊ValidKsizes _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 IV to feed the first block :property IV :access public ∇ r←get r←_iv ∇ ∇ set Value;val;valid ⍝ We must ensure the value fits requirements: valid←VKS⊃_algo.LegalBlockSizes.(MaxSize MinSize SkipSize) :If ~valid∊⍨⍴val←Value.NewValue val←valid[1++/valid<⍴val]⍴val :EndIf _iv←UCSN val ∇ :endproperty ⍝ This generates a random Initialization Vector ∇ r←RandomIV :Access public _algo.GenerateIV r←_algo.IV ∇ ⍝ This generates a random Key ∇ r←RandomKey :Access public _algo.GenerateKey r←_algo.Key ∇ :Property KeySizeBytes :access public ∇ ks←Get ks←⌊_algo.KeySize÷8 ∇ ∇ Set Value;v v←Value.NewValue _algo.KeySize←v×8 MMS[1]⌊←v ∇ :EndProperty ⍝ Ensures that _algo object has valid Key and IV ⍝ prior to any attempt to encrypt/decrypt anything ∇ ValidateKeyAndIv isEncrypting :If 0=⎕NC'_key' :If isEncrypting _key←RandomKey :Else 99 ⎕SIGNAL⍨'No key was provided for the decryption operation!' :EndIf :EndIf :If 0=⎕NC'_iv' :If isEncrypting _iv←RandomIV :Else 99 ⎕SIGNAL⍨'No initialization vector was provided for the decryption operation!' :EndIf :EndIf _algo.Key←_key _algo.IV←_iv ∇ ⍝ Encrypts the specified Data using provided key ∇ r←Encrypt2(d key) :Access public Key←key r←Encrypt1(d) ∇ ⍝ Encrypts the specified Data using preset key and preset initialization vector ∇ r←EncryptString d;⎕USING;ms;cs;cr :Access public ⎕USING,⍨←⊂'System' ValidateKeyAndIv 1 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 ∇ ⍝ Encrypts the stream to memory using provided key and provided initialization vector ∇ Encrypt3(s key iv) :Access public IV←iv Key←key r←Encrypt1(s) ∇ ⍝ Encrypts the specified stream to memory using preset key and preset initialization vector ∇ r←EncryptStream s;i;b;cs;ms;⎕USING ⍝ *** NOT TESTED *** ⎕USING,⍨←⊂'System' :Access public ms←⎕NEW IO.MemoryStream cs←⎕NEW CryptoStream(ms(_algo.CreateEncryptor ⍬)CryptoStreamMode.Write) ValidateKeyAndIv 1 i←s.Read(b,0,_BufferSize) :While i>0 cs.Write(b,0,i) i←s.Read(b,0,_BufferSize) :EndWhile cs.Close ms.Close r←ms.ToArray ∇ ⍝ Decrypts the specified data using provided key and preset initialization vector ∇ Decrypt(encryptedData key) :Access public Key←key r←Decrypt(encryptedData) ∇ ⍝ Decrypts the specified stream using provided key and preset initialization vector ∇ DecryptEstream2 encryptedStream :Access public Key←key r←Decrypt(encryptedStream) ∇ ⍝ Decrypts the specified stream using preset key and preset initialization vector ∇ DecryptEstream encryptedStream;i;b :Access public ms←⎕NEW System.IO.MemoryStream ValidateKeyAndIv(False) cs←⎕NEW CryptoStream(encryptedStream(_algo.CreateDecryptor ⍬)CryptoStreamMode.Read) i←cs.Read(b,0,_BufferSize) :While i>0 ms.Write(b,0,i) i←cs.Read(b,0,_BufferSize) :EndWhile cs.Close ms.Close r←ms.ToArray ∇ ⍝ Decrypts the specified data using preset key and preset initialization vector ∇ r←DecryptCipher encryptedData;b;ms;cs;len :Access public ⎕USING,⍨←'System' 'Dyalog' ValidateKeyAndIv 0 ms←⎕NEW IO.MemoryStream(encryptedData 0,⍴encryptedData) cs←⎕NEW CryptoStream(ms(_algo.CreateDecryptor ⍬)CryptoStreamMode.Read) ⍝ r←ms.ToArray b←⎕NEW ByRef,⊂⊂3/⍨⍴encryptedData :Trap ⍬ len←cs.Read(b 0,⍴encryptedData) :Case 11 99 ⎕SIGNAL⍨'Unable to decrypt data. The provided key may be invalid.' :Else cs.Close :EndTrap r←⎕UCS len↑b.Value ∇ :EndClass