This initial version adds support for cryptography and related tasks to the
newObjects ActiveX Pack1 family (AXPack1). The HashCryptStreams.dll is
distributed with the entire AXPack1 and the download links above point to the
full packages containing also the other components of the family. Of course,
this does not mean that you are required to redistribute all of them with the
applications you are building. You can find installable packages and ZIP files
with the AXPack1's DLL files from which you can get what you need and include it
with your applications (The list of all the packages for download is here).
It appears that exposing for download the whole family is more convenient than
providing separate downloads for each of its component.
1. Overview
2. How it looks in action
a) Symmetric cryptography algorithms
b) Hash and HMAC
c) RSA
3. FAQ
4. What to download
The initial version of HashCryptStreams lays the foundation for
cryptography support in AXPack1. This first version concentrates on the
infrastructure and the programming interface. It provides support for some of
the most popular symmetric cryptography algorithms, some hash functions with
HMAC support and the RSA algorithm. Over the same infrastructure more algorithms
will be provided with the next versions of HashCryptStreams enabling the
developers to choose from wider set of algorithms without need to change their
code.
What we have in version 1.0?
Hash functions with HMAC support: MD5, SHA-1, SHA-256
Symmetric cryptography algorithms: AES, DES and 3DES
Asymmetric cryptography: RSA algorithm
Goodies: Big number arithmetic (BigNumber object).
Programming interface standard.
Most of you have already guessed that we want to create some kind of
cryptography related programming interface standard with HashCryptStreams.
Obviously this may look strange when you know that there is a CryptoAPI in
Windows - so the question is why?
In contrast to the Windows CryptAPI HashCryptStreams defines a programming
interface at a lower level of usage of the cryptography algorithms. The
Windows API concentrates on providing standards based interface, while
HashCryptStreams does that on the algorithm level. The need of such a
programming interface appears when you need to deal with applications that do
not conform to the standards or applications using standards not supported by
the Windows Crypto API. In such case you need to do something yourself - pack
the data as required by the other application, perform some specific
operations and you have no choice but to go to a lower level.
Is it easy to use? As much as possible. The hard part is to learn
what custom or public standards you must obey in your particular case and then
use HashCryptStreams (often in combination with objects like SFBinaryData from
the AXPack1 core) to implement it.
I thought there were complete standards for cryptography, what all this
means?
In brief the situation is like this: You hear about certain algorithms and
their usage - for instance you hear talks about how DES is no longer
considered secure and one must move to 3DES at least or go for something even
better like AES for example. However this is not the whole story. The
algorithms are the simplest part of the applied cryptography, having them one
faces another problem how to achieve a common ground with the other
applications. One obvious problem behind all this is that most of the good
symmetric algorithms are block based and when you encrypt something you get a
cipher with size multiple of the block size and not equal to the size of the
original data. So, you need to record the original size (or at least the
remainder to the block size) when encrypting - in order to be able to truncate
the rubbish after decrypting back. Here comes the question how to pad the data
to the block size and so on and so on. Thus over the algorithms there are
other standards that define how the meta-data about the encrypted data is
packed. Unfortunately there are quite many applications following their own
way to deal with these and the other problems and very often you cannot just
call an encryption function and forget about the details. Once you are off the
area covered by the SSL (Secure Socket Layer) and the digital signature
oriented usage you would meet many variations of how and why the encryption
algorithms are used and HashCryptStreams aims at providing a way to enable you
write code for such scenarios even in VBScript/ASP.
HashCryptStreams will include in the next versions built-in support for the
most used PKCS standards, but will not go too much further than that. Instead it
will improve in its main goals - making it easier for the developer to implement
standard or non-standard cryptography schemes knowing only the requirements
about the data packing and the general features of the algorithms involved, but
not requiring him/her to know details about the specific algorithms.
How this looks in action
Lets first show a simple usage of a symmetric algorithm:
Set crypt = Server.CreateObject("newObjects.crypt.Symmetric")
crypt.Init "DES"
crypt.Key = "0123456789ABCDEF"
crypt.PadType = -1
cipher = crypt.Encrypt(mydata)
This is the simplest kind of usage when the whole data is processed in a
single step. Of course it can be processed in chunks:
Set crypt = Server.CreateObject("newObjects.crypt.Symmetric")
crypt.Init "DES"
crypt.Key = "0123456789ABCDEF"
crypt.PadType = -1
' Assume infile is some file already opened for reading
' and outfile is a file opened for writing.
While Not infile.EOS
chunk = infile.ReadBin(256)
If Not infile.EOS Then
' Do not finalize encryption until the last chunk of data
cipher = crypt.Encrypt(chunk,False)
Else
' This is the last chunk of data - finalize so that the
' last block can be padded (see the PadType above)
cipher = crypt.Encrypt(chunk,True) ' True is default for the second argument
End If
' Write to the output file
outfile.WriteBin cipher
Wend
Aside of what you can see above the Symmetric object also can give you
information about the block size of the algorithm. Knowing this you can perform
your own padding or relay on the PadType property which when set to -1 pads with
random bytes or repeats the specified value if it is > 0.
When you are doing something more than the basic operation you need more than
just the encryption algorithm. Here comes the usefulness of the AXPack1 family
as whole. One of the objects that would most often be needed with
HashCryptStreams is SFBinaryData (from the AXPack1 core DLL -
newobjectspack1.dll). What it gives you is advanced way to work with binary data
buffers in memory. Whatever language you use, VBScript, Javascript, NSBasic
etc., you would have problems working with binary data using the language
capabilities only. Even in some languages offering more in that area it would be
easier to relay on SFBinaryData for more efficient memory usage. In some cases
you may need to combine more different kinds of operations involving read/write
of streams, work with databases and so on. The fact that the AXPack1's objects
are designed to copperate easily will simplify such tasks.
To illustrate the above lets take an example where we would need to decrypt
some data. However, we will want to make it harder, so lets assume that a file
has been encrypted and the original file size has been encrypted with the file
contents (before the actual data). The code below can be write in various forms,
but we intentionally will use a way that involves more objects in order to
illustrate how the can be used together:
' Create the objects we need
Set crypt = CreateObject("newObjects.crypt.Symmetric")
Set sf = CreateObject("newObjects.utilctls.SFMain")
Set sfbd = CreateObject("newObjects.utilctls.SFBinaryData")
' Open the files
Set infile = sf.OpenFile(infileName,&H40)
Set outfile = sf.CreateFile(outfileName)
' Init the Symmetric encryption object
crypt.Init alg
crypt.Key = key
' We will decrypt only - so there is no need to care about the padding method this time.
' The encrypted file contains the original file size in its first 4 bytes
' However we cannot read just 4 bytes because the block size can be bigger
' (usually is). So, to ensure we need to read entire block in a memory stream.
Set mem = sf.CreateMemoryStream
' How much to read, better read more than needed than less
blocksToRead = (crypt.BlockSize / 4) + 1
mem.WriteBin crypt.Decrypt(infile.ReadBin(crypt.BlockSize),False)
' Why memory stream? Well, you can use SFBinaryData for everything.
' we just used that in this example to make the task easy to understand
' Now use the binary data object to consume the size
sfbd.Size = 4
mem.Pos = 0
sfbd.Value = mem.ReadBin(4)
' Now get what we need and write the rest to the output
' Lets assume that the original size is in big endian and not in
' the native for Windows little endian byte order - just to make the things
' harder
sfbd.ByteOrder = &H02
FileSize = sfbd.Unit(0,vbLong)
' Write the rest of the block to the output
mem.CopyTo outfile, crypt.BlockSize ' The number of bytes just needs to be bigger than the actual content
' mem is no longer needed lets dispose of it explicitly (not actually needed,
' it will be freed as the script completes anyway.
Set mem = Nothing
' Decrypt the rest
Do
chunk = infile.ReadBin(256)
If Not infile.EOS Then
bindata = crypt.Decrypt(chunk,False)
Else
bindata = crypt.Decrypt(chunk,True)
End If
' Write to the output file
outfile.WriteBin bindata
Loop While Not infile.EOS
' Truncate the output file to the size we read before
outfile.Size = FileSize
Of course, this can be done with less code, but this way we can see how the
different objects work together making the otherwise difficult problem a matter
of configuring certain objects to match what we have to work with.
HashCryptStreams goes further. It provides two alternative programming
interfaces for the same task - the first you can see in action above, the second
is a stream filter that can be used to provide abstract file/stream interface
which performs transparent encryption/decryption. Of course, this technique
makes sense if the application is complex enough to benefit from separation of
certain modules from the others. In simpler and more trivial usage scenarios
using the stream filter is hardly justified because of the added work needed in
order to make its usage transparent for the rest of the application. Here is a
basic code snippet that configures a chain of streams and stream filter and then
writes data through it - the data is encrypted while written. Of course, this
code is illustration, in the real world the configuring part should be in a
separate routine or module, while the code that uses it will be part of some
application's task:
Set sf = Server.CreateObject("newObjects.utilctls.SFMain")
' Open the original file (read only)
Set infile = sf.OpenFile(Server.MapPath("original-image.gif"),&H40)
' Create the SFStreamCrypt object
Set crypt = Server.CreateObject("newObjects.crypt.SFStreamCrypt")
' We will encrypt while saving the file, thus we are going to use
' only the Write algorithm - so set up it. Set the algorithm
crypt.WriteAlgorithm = myalg ' the name of the algorithm DES, AES etc.
' Set the key. This will fail if the key is not the correct length for the
' selected algorithm. Depending on how this is used it may be a good idea
' to check if the key is correct size and issue an error if it is not.
crypt.WriteKey = Request("Key")
' By default the Write algorithm is configured for encryption, but
' we will specify this explicitly for the sake of the example.
crypt.WriteDecrypt = False
' As the algorithms are working with fixed size blocks the result
' may not match the size of the encrypted data. Thus we need to know the
' original size when we are decrypting. The best way for us is to keep the
' size with the encrypted file. So we will write it before the file data.
FileSize = infile.Size
Set bd = Server.CreateObject("newObjects.utilctls.SFBinaryData")
bd.Size = 8 ' We reserve 8 bytes for our purposes
bd.Unit(0,vbLong) = FileSize
' We will write this in the file first - see below
' Now open the output file
Set outfile = sf.CreateFile(Server.MapPath("encrypted-image.bin"))
' To make the encryption part of the file write operation we need to connect
' the SFStreamCrypt object with the output file and write through it.
' Connect it
Set crypt.Stream = outfile
' In order to be able to write to the SFCryptStream we need to pack it into
' a SFStream object
Set outstream = Server.CreateObject("newObjects.utilctls.SFStream")
outstream.SetStream crypt
' Now write our binary data that contains the file size
outstream.WriteBin bd.Value
' And now read from the infile and write to the outfile through the stream chain
' For brevity we will transfer the whole file at once, usually this is done in small
' chunks in a cycle
outstream.WriteBin infile.ReadBin(infile.Size)
' Finalize the encryption - i.e. tell the SFStreamCrypt there will be no
' more data.
crypt.WriteFinalize
' Close everything
outfile.Close
infile.Close
Notice the two lines in bold. They are the lines that construct the chain.
The SFStreamCrypt object wont do anything if it is not connected to a stream
object that actually controls some kind of a physical stream - file, network
connection or something else. The part where we attach a SFStream to the
SFStreamCrypt object is needed because we write to the created chain of stream
filter and real stream from the script. If there was a component or an external
application that can work with the standard IStream COM interface we could have
omit that and pass the so configured object in the crypt variable to it
and leave it to do the writing. Thus the stream filter may require some more
coding but it enables you to offer to 3-d party components and applications a
stream in which they can write (or read if the other direction is used) and thus
make them perform encryption/decryption even if they do not support such
feature. See details in the documentation (download NDL and
see SFStreamCrypt in it)..
What about the hash and HMAC functions?
The interface to them is very similar to the programming interface for the
symmetric cryptography algorithms. The difference is that the data is only
inspected and the application uses the generated hash/HMAC. Again there are two
kind of objects for that purpose - one providing direct access to the algorithms
(HashObject) and one stream filter (SFStreamDigest). Like in the case with the
symmetric algorithms they do the same but in different manner and again
HashObject is the general purpose programming interface, while the
SFStreamDigest is for applications that aim at isolation between their parts and
providing added functionality transparently. All the same, the stream filter
version does not worth to be used in simper scenarios, but can enable you to
force modules, components or applications to generate hash/HMAC even if they do
not support such feature.
Here we will illustrate only the HashObject which obviously will be more
frequently used than the specialized stream filter programming interface version
(SFStreamDigest - it is used much like the SFStreamCrypt - see details in NDL
and the included examples).
The simplest way to generate hash is like this:
Set h = CreateObject("newObjects.crypt.HashObject")
h.InitHash alg ' MD5, SHA1, SHA256 etc.
h.HashData somedata
digest = h.Value ' generated hash as hexdecimal
' Or if you want the generated hash as binary (VT_UI1 | VT_ARRAY)
digest = h.BinaryValue
' If you want to reuse it
h.Reset
' Then you can hash another data
Note that HashObject offers some flexibility about the data you pass to for
processing. somedata in the above example can be a string or binary data
whichever is more appropriate. Hash functions are very often used over text
directly, most often over single byte encoded (even ASCII only) texts. To enable
easy usage in such scenarios the HashData method has second optional parameter.
If you pass a string variable as data argument you can specify the code page
that must be used for conversion before the hash is generated. I.e. do not
forget COM works internally always in UNICODE, when you pass a string to a
function if you want it to be processed as ANSI text some code page must be used
for the conversion. By default the default code page for system is used, but you
can specify another. It is not customary practice to hash UNICODE texts, but
this is also supported - if you specify code page -1. For example:
h.HashData sometext, 1251
Will hash sometext after converting it internally through the Windows Cyrillic
code page.
What about HMAC? It is simple the same code with one more line will do the
job:
Set h = CreateObject("newObjects.crypt.HashObject")
h.InitHash alg ' MD5, SHA1, SHA256 etc.
h.HashData somedata
h.Key = somekey
digest = h.Value ' generated hash as hexdecimal
' Or if you want the generated hash as binary (VT_UI1 | VT_ARRAY)
digest = h.BinaryValue
' If you want to reuse it
h.Reset
' Then you can hash another data
When bigger amounts of data must be processed it is not convenient to pass
all the data in a single step. For that purpose instead of using the HashData
method you can use the pair HashUpdate/HashFinalize methods which do the
same but you can call HashUpdate many times to pass more and more data and
finally call HashFinalize to end the process and obtain the digest of all the
data you have put through the multiple calls to HashUpdate.
RSA
As we mentioned above the RSACrypt object from HashCryptStreams exposes the
base algorithm and means to generate keys. From that point further the actual
usage would differ depending on the standards or the custom requirements you
must meet. A support for some PKCS standards will be added in the next versions.
The usage is as simple as:
Set rsa = CreateObject("newObjects.crypt.RSA")
rsa.PublicExp = pubkey_exp_part
rsa.Modulus = pubkey_modulus_part
cipher = rsa.Encrypt(data)
The other operations are as simple as this one and require only a few lines
of code. The real trouble with RSA is how to embed it into your application. You
need to decide what to encrypt with it, devise a format in which the data is
prepared for encryption/decryption or choose a standard that defines such a
format. If you are new to the public key cryptography the chapter About the Public Key algorithms
in NDL will give you the principles not burdening you with
the mathematics of the algorithm. Strangely on the WEB there are many and many
articles about the algorithm itself, but only a few comment even partially the
algorithm's general usage concepts. To fill the gap we placed that article in
the documentation of the library - it describes why there must be standards or
at least conventions about its usage, the features of the algorithm (and the
similar ones) that naturally define its possible area of applications and usage
patterns.
FAQ
Q: Where is the documentation
A: In NDL. Download and install it. Lookup in the index the
corresponding object (HashObject, Symmetric, RSA etc.) or go through the
contents tree to the newObjects ActiveX Pack1/HashCryptStreams
Q: Does the library use the Windows CryptAPI
A: No, it is completely independent implementation, may be not the
fastest available but available for all the Windows variants (desktop, CE/Pocket
PC/Smartphone) in the same form with the same features everywhere. We may
publish the extension API that would allow additional algorithms to be
implemented by other vendors and accessed through the same programming
interface. However the time will tell if there is a real need for this.
Q: How many and what kind of algorithms will be included in future
versions
A: Only the most popular algorithms will be included in the DLL.
Probably up to 5-6 more symmetric encryption algorithms and as many other hash
functions. We have not decided yet about this but it is possible that we will
include also some simple encoding algorithms (like Base64 for example) in this
DLL in the form of symmetric algorithms without a key.
Q: How much it costs?
A: What you see in version 1.0 is freeware and will remain such. Some of
the algorithms we will add later will require a license (one license will cover
them all). Thus the same DLL would be possible to be used as freeware (With
support for the part of the algorithms) when no license is available and with a
license one will have more algorithms available. We will try to keep the
freeware border at a level that enables most application build for the general
public to cope without a license.
Q: Does the DLL depend on other modules?
A: No except for the stream filters (SFStreamCrypt and SFStreamDigest). If you
want to use them from ASP/ALP, NSBasic or other environment on similar level you
would need to drive them through the SFStream object. However this is about
usage and not a requirement - the library will work alone, it would be just more
convenient to have also the AXPack1 core components in order to simplify the
related tasks you may need to perform. The included examples concentrate on this
kind of usage, but most developers will not have trouble to use the library
without the AXPack1 core if the size of the files redistributed with their
application is crucial.
What to download
This page is an introduction and place for information about the
HashCryptStreams.DLL. This library is part of our newObjects
ActiveX Pack1 family (AXPack1) which we distribute as whole from 2003. Thus
all the downloads by default contain all the AXPack1 binary files including
HashCryptStreams.DLL. With the growth of the AXPack1 family it became a problem
for the developers to gather all the needed files from different pages, thus we
packed everything together. AXPack1 is a component library and while it includes
an application that provides minimalistic programming environment (MicroScriptHost)
it is mainly a library that is used by other applications. For example
applications written in ALP, ASP, NSBasic,
VB and virtually any other programming tool that has support for COM Automation.
Thus the library reaches the end-user computers and devices as part of something
else. The installable downloads are for developer's convenience in the first
phases of the development when the application is not packed with an installer,
for usage on WEB servers where the AXPack1 is used by ASP and other
applications, for testing and performing administrative tasks in minimal but
platform independent scripting environment and so on. These, installable
downloads, cover only the most popular platforms on which AXPack1 is often
needed and platforms on which programming is likely to be performed, everything
else is supplied in raw form - the binary files in ZIP files.
The complete list of all the AXPack1 downloads is here.
Quick suggestions:
- If you are going to use AXPack1 on an IIS server download the PC only
installable version and install it on the server machine.
- If you are going to develop for Pocket PC (regardless of the programming tool
you are going to use) download the PC/Pocket PC combined download. After
installing it on the PC you can invoke at any time installation to a Pocket PC
device from the created start menu group.
- If your application will be packed with an installation in the end of its
development gather the ZIP files containing binaries for the platforms on which
the application will work and configure your installer to install the DLL-s from
AXPack1 that you actually use. Get only the files you actually need - for
instance it is very doubtful that you would want to use both SQLite COM and
SQLite3 COM modules, thus include only the DB engine you have choosen.
- Want to play with scripting on some other device, smartphone, custom Windows
CE device etc. Download the ZIP file with binaries for the device's OS version
and processor type, copy then to the device (does not matter where - in a
directory on a memory card for example). Then use a file manager you have on the
device to start nwmicrohost.exe. From it you can register COM DLL manually
without need of installer application - so register the DLL you are going to use
and create some scripts. If you are not sure for the processor of the device get
the most likely archives and try to start nwmicrohost.exe from each of them -
the one that works is obviously for your platform (some devices come really
bare-boned and it is not impossible to get a device with no means to find out
what you have inside other than testing or opening it).