Discuss this help topic in SecureBlackbox Forum

Decrypting data with symmetric algorithm

Symmetric encryption is normally used where you need to encrypt large amounts of data with a secret key known both to encrypting and decrypting parties. With SecureBlackbox you use a dedicated TElSymmetricCrypto class to perform encryption and decryption.

Decrypting data symmetrically is performed in the following steps:

  1. Create a symmetric crypto factory object: TElSymmetricCryptoFactory factory = new TElSymmetricCryptoFactory();
  2. Use the factory to create a crypto object of the appropriate algorithm: TElSymmetricCrypto crypto = factory.CreateInstance(SBConstants.Unit.SB_ALGORITHM_CNT_AES256, TSBSymmetricCryptoMode.cmDefault); By default, encryption and decryption is performed in cipher block chaining (CBC) mode. This is the most common encryption mode used in a huge variety of security environments. If you need to decrypt data encrypted in a different encryption mode (such as CFB, CTR or ECB), you can specify that via the second parameter of the factory's CreateInstance() call.
  3. Create a key material object and assign the values of the secret key and the IV (if any chaining mode is used) to the Key and IV properties of the object: TElSymmetricKeyMaterial km = new TElSymmetricKeyMaterial(null);
    km.Key = keyBuf; // for AES256, keyBuf should contain a 32-element byte array containing the secret key value
    km.IV = ivBuf; // for AES256, which has a block of 16 bytes, ivBuf should contain a 16-element byte array containing the IV value
  4. Assign your key material object to the crypto object's KeyMaterial property: crypto.KeyMaterial = km;
  5. You're all set now and can proceed with data decryption. You can provide encrypted data as a byte array or a stream. Note that the length of the output (decrypted) data will be the same as that of the input data, minus up to two block sizes, depending on the encryption mode.
    Buffer-based decryption supports preliminary 'length calls' approach used in a variety of environments:
    
    byte[] inBuf = <encrypted data>
    // Setting outBuf and outSize to null/zero to indicate that our first call is a length getting call
    byte[] outBuf = null;
    int outSize = 0;
    
    // Finding out about the output length - this may be approximate
    crypto.Decrypt(inBuf, 0, inBuf.Length, ref outBuf, 0, ref outSize);
    
    // Allocating an array for the output data
    outBuf = new byte[outSize];
    
    // Decrypting the data
    crypto.Decrypt(inBuf, 0, inBuf.Length, ref outBuf, 0, ref outSize);
    
    // Copying the decrypted data to a dedicated buffer. Note that outSize returned by this call may be smaller than that of the first length getting call
    outBuf = SBUtils.Unit.CloneArray(outBuf, 0, outSize);
    			
    Stream-based approach is much simpler: crypto.Decrypt(inStream, outStream);

If certain complicated scenarios you might need to decrypt data chunk-by-chunk. If this is the case, do the following:

  1. Set up the crypto object as above.
  2. Before decrypting, call the InitializeDecryption method of the crypto object: crypto.InitializeDecryption();
  3. Decrypt data in chunks via a series of DecryptUpdate() calls. Concatenate together the pieces of decrypted data returned to you by every call. crypto.DecryptUpdate(inBuf, 0, inBuf.Length, ref outBuf, 0, ref outSize);
    outBuf = SBUtils.Unit.CloneArray(outBuf, 0, outSize);
  4. When you've finished passing all the encrypted data to DecryptUpdate(), finalize the decryption with FinalizeDecryption() call: crypto.FinalizeDecryption(ref outBuf, 0, ref outSize);
    outBuf = SBUtils.Unit.CloneArray(outBuf, 0, outSize);
    Note that, depending on the encryption mode, FinalizeDecryption() may return the trailing piece of decrypted data. Remember to append it to the decrypted data previously received from DecryptUpdate().

How To articles related to low-level cryptography

Discuss this help topic in SecureBlackbox Forum