category-group: security
layer(s): 2, 7, 10 header file(s): z_crypt.h, z_crypt_header.h, z_uacct.h synopsis.
Security is about protection; protection of data comprises the bulk of the security group; and encryption comprises the bulk of data protection. So, this group contains mostly encryption software. It also includes checking whether a user (or possibly a software object) has access permissions. This is done via the "user account" component-object (uacct_o), which gives a program a tool to manage user accounts. In the Z Directory, the containers for encrypting and decrypting data are strings (string_o) . Since the string object handles binary data as well as text, this means binary (non-text) files can be encrypted via the string_o class. classes in this group: filecrypt_header_o, iocrypt_o, multicrypt_o, crypto_o, nocrypt_o, ROT13crypt_o, coolhash_crypt_o, nilecrypt_o, vettra1_crypt_o, chambran_crypt_o, blowfish_crypt_o, twofish_crypt_o, DES_crypt_o, RSA_crypt_o, Rijndael_crypt_o, uacct_o description.
All encryption objects here conform a standardized pattern. Their usage is all the same, with a few exceptions, which will be duly noted. Using the encryption components is a straightforward process:
- create (instantiate) a crypto object;
- set up a string object (in binary mode) that contains the data to encrypt;
- set the crypto password (some ciphers don't require one);
- encrypt the data block;
- decrypt the data block. if a different crypto object is used, it obviously must have the password set (RSA_crypt [aka RSA] has some differences as to the keys used).
- The output size of some methods might be larger than
the input size. That is, one bye of data may generate
2 or 4 bytes of encrypted output. For example:
nilecrypt_o: 1 input byte creates 2 output bytes
RSA: input block size of 10, but output is in units of 11 bytes - Some methods may require the input block to be in n-byte
multiples.
For example: chambran_crypt_o: input and output must be in units of 4 bytes (that is, the numer of bytes to encrypt should be 4, 8, 12, ... 4200, 4204, 4208, .. etc) DES_crypt_o: input and output sizes should be in multiples of 64 bytes. RSA_crypt_o: input and output sizes should be in units of 16 bytes. Rijndael_crypt_o: you have a choice of these 3 input and output sizes: 16, 24, or 32 bytes. - By default, crypt_o may add "padding" to the encrypted result. Thus, when a [byte string] block is encrypted, the length of the the block may be longer than what you started with. This is true if the input size is not a multiple of the block size of the encryptor and "auto-padding" is used (see the discussion below). However, when using auto-padding, the decrypted block will be stripped of the extra pad. Thus, the final decrtyped block (whether text or binary data) will be the same as what you started with.
- The password may need to be of a specific length. In particular, with Rijndael_crypt_o, the key must be exactly one of 16, 24, or 32 bytes long.
- The password-key usage can get complicated. In particular, RSA requires 2 keys (one is "public", the other is "private"). See the page for RSA_crypt_o for an explanation of RSA key generation and usage.
- There may be additional usage requirements. Some ciphers may require a 1-time initialization performed before using it. Rijndael_crypt_o needs a call to 'gen_key()'. Some ciphers require setting a second password (often called "the salt"). There can be other nuances, specific to the cipher.
If you want to encrypt some text, don't want to bother with a password, you don't consider the contents that important, and you might possibly reuse the same data space without having to resize it, you may consider ROT13crypt_o . If you don't want to remember a password, and you don't mind the output-target space being twice as big as the original data, you can use nilecrypt_o . For more secure encryption, you can step it up to vettra1_crypt_o (output size is 1:1). If the data is sensitive, DES_crypt_o may suffice. However, the very popular DES has been broken a long time ago. Better to use blowfish ( blowfish_crypt_o ). Bruce Schneier, the author of blowfish, realized he could make a much stronger cipher, so later he created twofish. Many consider twofish cipher very strong. If your data to encrypt is really important and you don't want anybody else getting to it, including a fedreral agency trying to pry into your data using a team of cryptographers, use RSA_crypt_o (an implementation of RSA) or Rijndael_crypt_o . Keep in mind that for RSA you'll have to manage two [machine-generated] passwords that are impossible to memorize; they look like these:
"176F6260A946AF8B8BBD9D1#108D58CF0F96E51CB72215B" "2ECDEE938A9F3765368111#B3D4F3EC4DA6E12AF943"The pages for each of our encryption classes are fairly brief, as their member functions are almost all the same. In many cases, the signiture set of the member functions are exactly the same. Those pages will focus on explaining the nuances unique to the particular encryptor-cipher. The set of encryptor objects form a 2-level tree. The abstract class crypto_o defines up the interface for all encryption algorithms implemented in the Z Directory. Subclasses from crypto_o provide the classes that do actual encryption and decryption. The current roster (as of 2017) of the Z Directory encrypors is given by the following table ("BS" referes to "Block Size"; the first value is input block size, followed by output block size). The encryption algorithms are ordered (approximately) from weakest to strongest:
name | algorithm | key type | key size | BS | description |
---|---|---|---|---|---|
nocrypt_o | nocrypt_o | [none] | n.a. | 1, 1 | this does absolutely no encryption. It exists for testing programs, or learning the Z Directory API. The output is cleartext - the same as the input. You might find use for it to create an implementation of the unix 'cat' program, or to copy bytes from A to B. |
ROT13crypt_o | ROT 13 | none | n.a. | 1, 1 | This does "encryption" via a simple bit rotation. It is the most elementary of encryption methods. There is evidence it was devised during Roman times. It should not be used for any serious data encryption. It uses no key, and simply maps one letter to another. This is done by adding an offset to a value (ie, 'A' -> 'G', 'B' -> 'H', 'C' -> 'I", etc). ROT-13 is also known as the caeser cipher. It may dissuade a person with no knowledge of cryptography, but certainly not the determined hacker. |
coolhash_crypt_o | Cool Hash | none | any (internally, 16 bits) | 1, 2 | This encryption method, named after contributor Rob McCool (our thanks to the Regents of the University of California). It is a keyless, and I/O is 1:2 (1 byte in makes 2 output bytes). Though more complex than ROT-13, this is a weak encryptor. WARNING 1: this can only be used for text data, eg, numbers and letters. Also, the key gets distilled to a 4-byte u_long. Hence, this algorithm is fairly useless as a general-purpose encryptor. WARNING 2: As of 2017, coolhash cipher is broken: the decrypted output is garbage. It does not work. Don't use it! (until further notice) |
nilecrypt_o | custom algorithm | none | n.a. | 1, 2 | this keyless cipher encrypts data by performing a series of transformations using the data block itself as the password. Because of this, we consider nile encryption to be a weak encryptor. The encrypted block is double the size of the (input) data block. |
vettra1_crypt_o | Vettrasoft's custom cipher | symmetric | 1 .. 4,095 | 1, 1 | An encryption method based on our own (proprietary) ideas. This was created at Vettrasoft in 1984. The proprietary algorithm works in a very different way from most any other cipher, and we keep this secret. The "1" in the class name designates that it is Vettrasoft's first encryption algorithm. We have plans for a far more complex, stronger cipher algorithm (TBA). The vettra-1 cipher should be considered to be of low to medium-grade quality. It has not, as of this writing (2017) been examined to assess its quality, and (as far as we know) no attempts to hack or crack it have been done. . Prior to 2017, the Achilles Heel of this encryptor was its password: it was only 1 byte long! Although you could supply a password of any size, internally it was "boiled down" to 1 byte. At the time it was created, the cipher was simply an experiment. With such a password problem, it was obviously vulnerable to brute-force attack (simply trying all possible passwords) and thus clearly was of no use as a true encryptor. This was remedied in January 2017. Now you can use a password of any length up to 4,095 bytes (and: the longer, the better). |
chambran_crypt_o | a cipher by Bill Chambers | symmetric | [< 1536 bytes?] | 4, 4 |
The author of the algorithm, Bill Chambers, calls this a
'cryptographic pseudorandom number generator', which he
created in 1995 (with some parts by Bob Jenkins). We
don't have much info on this. It is a block cipher
using S-boxes and other modern goodies. Bill pointed
out that cipher algorithms and random number generators
have much in common.
The data blocks must be a multiple of 4, in order to get
correct round-trip encryption-decryption; otherwise, there
may be [up to 3] "extra" garbage bytes at the tail of the
decrypted block.
Note that only recently (2017) this encryptor functioned correctly. Vettrasoft would like to see more testing and usage of this cipher. |
DES_crypt_o | Data Encryption Standard | symmetric | 28 - 64 bytes | 64, 64 |
DES: the original government-sponsered encryption algorithm,
is a famous encryption method, in wide use in the 1970's
and 1980's. In this implementation, the key should be 64
bytes long, although it can be less. However there is a
minimum size: 28 bytes. If you provide a key longer than
64 bytes, the excess is quietly discarded.
This encryptor should not be used on very short blocks of data (eg, under 80 bytes), and in fact, will not work on input 64 bytes or less. In order for the class to work on very short data of 63 bytes or less, we apply other cryptosto the data block. DES was mandated in 1975 by Federal Information Processing 40FR12134. |
blowfish_crypt_o | blowfish | symmetric key block cipher | [1-56] bytes | 8, 8 |
According to some, blowfish is "slowly gaining acceptance
as a strong encryption algorithm"
(www.netaction.org/encrypt/guide.html)
The blowfish algorithm was created in 1993 by Bruce Schneier. It was intended to be an alternative to DES. Although at the time it was considered strong, it has been superceded by twofish (by the same author). |
twofish_crypt_o | twofish | symmetric key block cipher | [1-56] bytes | 16, 16 | Both blowfish and twofish were created by Bruce Schneier. Twofish is a replacement for blowfish. Note that twofish has not recieved as much attention as some other cryptos, so it may be useful as a strong encryption algorithm. |
RSA_crypt_o | RSA | asymmetric key | (unsure) | 10, 11 | RSA is one of the strongest
encryptors created to date.
It has some quirks: you cannot supply your own password.
Rather, one needs to generate a password pair.
Also, the decrypted output comes in blocks of 11 bytes,
so often the output string has a few bytes extra. With
this you may want to keep track of the original (input)
data block's length.
.
Here is a sample key:
162AD5828539A3EE4E0ABB#4AB4CA7D38A434B5C1ED You need to call RSA_crypt_o::generate_keys() to create a set of keys (1 public, 1 private). |
Rijndael_crypt_o | Rijndael ("AES") | symmetric block cipher | 16/24/32 bytes | 16/24/32 | The name Rijndael is often confused with AES, or Advanced Encryption Standard. Briefly, AES was a contest made by NIST, and Rijndael was the winner, in 2001. The algorithm was created in 1998. . The length of the Rijndael key must be specific: 128, 192, or 256 bits (16, 24, or 32 bytes). The block length is the same as the key length used. Given a 128-bit key, it has been estimated that the fastest computers on Earth using brute-force would need billions of years to crack Rijndael-encrypted data. And that's with the smallest of the 3 key sizes. 'nuff said. |
file type & size | Nile | DES | Rijndael | |
---|---|---|---|---|
4.5 MB binary file (non-exec) | 0.35; 0.91 | 1.14; 1.01 | 0.57; 0.57 | 1.52; 1.52 |
65 MB installer program (gnucash) | 0.35; 0.85 | 0.83; 0.80 | 0.58; 0.57 | 1.06; 1.37 |
All the encryption objects here have the same basic usage, with a few minor differences. Unlike message transport, you need to select the cipher type in advance: chambran_crypt_o, blowfish_crypt_o, DES_crypt_o, RSA_crypt_o, Rijndael_crypt_o, etc. They are all sub-classes of crypto_o. That class is not useful to the client application, except perhaps if you want to see which member functions need to exist in subtypes. The basic methodology is to create a cipher instance, set the password, then encrypt or decrypt a block of bytes. The block must be put into a properly-prepared string object. Typically, the string object is put into binary mode and the block size is prepped so that it matches the "chunk size" of the cipher. The example [below] contains a concise example of how to use the various cipher classes. note.
The encryption components were formerly in their own group, "crypt". You may see references in the documentation to this name (which is not a gang). This documentation often refers to a "cipher". This is equivalent to "encryption algorithm". We use these terms interchangeably. Vettrasoft is not specifically in the encryption algorithm business, so for the most part, the source code comes from the public domain, was created elsewhere, and has been retrofitted to work in the Z Directory framework. One of the features provided in the set of encryption classes is "auto-padding". This is used when an encryption algorithm requires a specific input block size. For example, Rijndael operates in blocks of 16, 24, or 32 bytes; DES uses 64-byte blocks; Chambers-Rantgen blocks are 4 bytes long. If you are encrypting a file, it is unlikely to be an exact multiple of such sizes. If using auto-padding, the last block, if it falls short of the block size, will recieve extra bytes so that the data "pads out" to fit the block size. During the decryption process, the last few bytes (from 1 to [n] bytes, where [n] is the cipher block size) are examined to see if it matches the bytes in the padding. If so, those bytes are discarded from the plaintext output. Thus, the application does not need to worry about block sizes. This feature is on by default, and can be turned off by invoking the function set_autopad(FALSE) prior to encryption. There is a risk that your data may match that of the data pad in exactly the expected location (same data in the same place). The pad is carefully crafted to minimize this risk. Also, you can set your own pad string by calling set_pad() with a string whose length matches the cipher block size prior to doing encryption / decryption. Although some claim that encrypting a block of data already encrypted with another method doesn't buy you any more protection, Vettrasoft does not buy this claim, and you can readily re-encrypt (many times) with the Z Directory multicrypt_o encryption component. Suppose you have 1,000 characters of text, and you encrypt it with DES. Worried about the proliferation of DES cracker hardware devices, you re-encrypt the DES-encrypted block with RSA. Just remember to decrypt it with RSA, then DES (reverse order) to get back to clear text. If not using "auto-pad" mode, you will need to manually handle the block sizes, being careful when the output block size is different from the input block size, and making sure that the output block size ("chunk size") is correct. Thus, a chunk size of 16 indicates the input block length must be in multiples of 16. 256, 1600, 2400, and 11040 are valid block sizes. 15, 235, and 1590 are not). disclaimer: Vettrasoft wishes to acknowledge the use of various encryption methods not developed by Vettrasoft. Regarding any copyright issues: If Vettrasoft Corporation recieves any monetary compensation related to encryption algorithms contained within Vettrasoft products (eg, Z Directory archive libraries), such compensation is not for the code or algorithm itself (which is freely available in the public domain), but rather, for the construction of a software delivery system that provides a uniform interface to such code, including the work applied to (and not done by the original author) in making such software functionable in a clean, environment-independent framework such as the Z Directory by Vettrasoft. acknowledgements: thanks to:
coolhash_crypt_o : the Regents of the University of California (and Rob McCool);
chambran_crypt_o : Bill Chambers
RSA_crypt_o : Although the implementation of RSA here is external to the RSA Data Security, Inc., we thank them for their contribution to the evolution of RSA and any algorithms they created that made it into here.
blowfish : Bruce Schneier, creator of the blowfish algorithm.
twofish : Bruce Schneier (again).
Rijndael : Raif S. Naffah and Paulo S.L.M. Barreto (and CodeProject.com) for making this great AES crypto available. A note about "methods" within a given encryption class: Some of the encryptors have "method types". These are simply different implementations of the given encryption methodology, invariably by different authors. Vettrasoft may more may not publish reports about the quality or peculiarities of these implementations. We will no doubt provide updates about the differences (or similarities) of different methods. When using a multi-method encryption object, you should probably stick to a specific one. There will always be a default in the case of multi-method encryptors. examples.
The krypt program source code (see the sample downloads page) provides a wealth of information for using the cipher classes described here and the Z Directory in general. The following example is a fairly involved case of using 2 ciphers to encrypt some text.
Some points:
- When using multiple ciphers, you can use a pointer to the base class (crypto_o) for repititive operations.
- A substantial amount of the work in this example goes to computing and managing block sizes. Buffer management in this example can be extended to the other Z Directory cipher objects.
- In the case of non-stream ciphers, eg where the input and / or output bock size is not 1, or when the input / output size ratio is not 1, the size of the container (the string object) will probably need to be resized. In doing this, the original size of the data is lost. It is up to you to keep track of this. One possible solution is to encode the data (and possibly block size) into a header for the output (encrypted) block. This is actually done in Vettrasoft's krypt program (see download page). However, such additional functionality is not included in the layer 2 security-cryptography objects.
- When using Rijndael or RSA, other [set-up type] functions are required.
//-------------(BEGIN-SOURCE-CODE-BLOCK)-------------------------------- #include "stdafx.h" #include "z_crypt.h" #include "z_file.h" #include "z_mathsubs.h" char *enemy_of_state = "the CIA and FBI, they don't want anybody to know about the plane crash.\n\ And they will kill - by any way possible - anyone that wants to blow\n\ the whistle on them, about the rendition flights that The Agency was using,\n\ flights to and from Guantanamo. This secret information, commonly known\n\ in Colombia, must not be revealed."; int main (int argc, char *argv[]) { crypto_o *px = NULL; // make pointer, for loops nilecrypt_o ciphero_nil; Rijndael_crypt_o ciphero_rij; string_o password ("abracadabra"); int i, ie, ie2, factor = 1; size_t in_siz = 1, ot_siz = 1, orig_size; size_t nb_in, nb_out; string_o bytes_in = enemy_of_state; // str length is 323 bytes string_o orig_text = bytes_in; // make a "backup" copy string_o bytes_ot; orig_size = bytes_in.size(); // "push" size, 4 later restore ciphero_rij.set_keysize (32); ciphero_rij.set_blocksize (32); ciphero_rij.set_mode (zcrypto_mode_ECB); bytes_in.setmode_binary(); // make so we can mold the bytes_in.setmode_sticky(); // strings and not worry about bytes_ot.setmode_binary(); // whether the sizes have been bytes_ot.setmode_sticky(); // set to whatever we want for (i = 0; i < 2; i++) // loop twice, to compute max { // input & output block sizes switch (i) { case 0: px = &ciphero_nil; break; case 1: px = &ciphero_rij; break; } px->set_key (password); // SAME PASSWORD, EACH CIPHER nb_in = px->input_chunksize (&ie); // min block size of data input nb_out = px->output_chunksize (&ie); // usually 1x, 2x of input size factor *= nb_out / nb_in; // this just keeps growing in_siz = z_lcm (in_siz, nb_in); // find lowest poss. multiple ot_siz = factor * in_siz; // output size is mult of input } in_siz = z_ilum (bytes_in.size(), in_siz); // get multiple of "in_siz" bytes_in.force_size (in_siz); // expand size to 11 * 32 = 352 ot_siz = factor * in_siz; // again, size is mult of input bytes_ot.resize (ot_siz); // 2 * 352 = 704 //.......................................................... // encrypt the data // round 1: output size goes to 2 * 352 = 704 // round 2: output size unchanged (1:1; eg, 704 bytes) //.......................................................... for (i = 0; i < 2; i++) { if (!i) px = &ciphero_nil; else { ciphero_rij.reset_chain(); bytes_in = bytes_ot; // transfer 1st-round encrypted px = &ciphero_rij; // to make it new the input } ie = px->encrypt (bytes_in, bytes_ot, &in_siz); } ot_siz = in_siz; string_o crypted = bytes_ot; string_o clear = ""; //.......................................................... // we'll write out the encrypted data block to a file //.......................................................... file_o f_out; f_out.set_name ("hidden.txt"); f_out.setmode_binary(); ie = f_out.put_bytes (bytes_ot, &ot_siz, &ie2); //.......................................................... // decrypt the data. note the reverse order of obj. pointer //.......................................................... ciphero_rij.reset_chain(); // MANDATORY! for (i = 0; i < 2; i++) { if (!i) px = &ciphero_rij; else // transfer output -> input { px = &ciphero_nil; crypted = clear; } ie = px->decrypt (crypted, clear, &ot_siz); } clear.force_size (orig_size); // "pop" the original size if (clear == orig_text) std::cout << "STRINGS MATCH.\n"; else std::cout << "No MATCH.\n"; return 0; } //-------------(END---SOURCE-CODE-BLOCK)--------------------------------history.
??? 12/28/1984: vettra1_crypt object created ??? 02/29/1996: bug fixed in DES Sun 11/17/1996: coolhash bug fix, for 'binary' data Tue 11/18/1997: min() problems in vettra1 crypt ??? 11/06/1998: bug fixed in ROT-13 Thu 11/28/1996: filecrypt_header_o initially created Sun 03/23/2003: filecrypt_header_o added to Z library Wed 04/06/2011: DE-ACTIVATED coolhash_crypt_o (doesn't work) Tue 04/12/2011: "simple hash" reborn (via Rob McCool); RSA_crypt return Fri 04/15/2011: Rijndael added to Z Directory Sat 01/14/2017: work on blowfish (impl. by Gaby Abed) started Wed 01/18/2017: twofish added to the Z Directory Fri 01/20/2017: 8:15am: twofish implementation working 100%limitations.
iocrypt_o is intended to be used for processing many lines of input, and writing the encrypted (or decrypted, if going in reverse) output to files. With this object you can use multiple encryption algorithms chained together, each with its own unique password. Vettrasoft plans to add a multicrypt_o class, at a lower layer, which provides multiple chained encryptors (plus a uuencoding option) but doesn't have all the bells and whistles for reading and writing I/O to and from stdin or files. Having 2 separate classes would allow applications to use the simpler object to do a single encode-decode. The iocrypt_o class is somewhat cumbersome to use and oriented towards processing multiple lines of input.