REBOL
Docs Blog Get-it

REBOL Encryption

SDK Documentation

Contents

Overview
Encryption Strength
Symmetric Key Encryption
Encrypting/Decrypting Data
Blocking/Padding
Examples
Creating a pseudo-random 128-bit encryption key
Encrypting a file
Decrypting a file
RSA Public Key Encryption
Functions
Examples
Generating a new 1024-bit RSA key
Encrypting a text file using RSA
Decrypting a text file using RSA
Signing a text file using RSA
Verifying a signature using RSA
DSA Digital Signatures
Functions
Examples
Generating a new 1024-bit DSA key
Signing a text file using DSA
Verifying a signature using DSA
DH Diffie Hellman Key Exchange
Functions
Examples
Generating a new DH session key
Computing the key for symmetric key encryption

Overview

The following types of data encryption are available:

Encryption Strength

Due to United States export laws, full strength encryption is not available in all countries. To determine the strength of your version, use the crypt-strength? function.

The crypt-strength? function returns the maximum encryption strength as a word. The result can be:

fullFull strength encryption available.
exportReduced strength encryption.
noneNo encryption available.

For example,

if crypt-strength? [print "Encryption is available"]

will indicate that encryption is available. Or:

if crypt-strength? = 'full [print "Full encryption strength"]

will indicate that full strength encryption is available.

Symmetric Key Encryption

Symmetric key encryption uses the 'crypt scheme of the REBOL port mechanism to encrypt and decrypt data. To create a crypt port use

crypt-port: make port! [
    scheme: 'crypt
    algorithm: 'blowfish
    direction: 'encrypt
    strength: 128
    key: encryption-key
    padding: true
]

The scheme is always 'crypt. The algorithm currently can be 'blowfish or 'rijndael. The direction is 'encrypt or 'decrypt. The strength can be the number of bits (up to the maximum strength supported by the algorithm), or 'export for the maximum strength supported in the export version.

Padding should usually be set to true, except if interoperability with other (non-REBOL) implementations of the encryption algorithms is required. Please see the "Blocking/Padding" section for more information.

The encryption key has to be set to a binary of at least the size specified in strength. The same key has to be used to both encrypt and decrypt data.

Other parameters that can be set in crypt ports include:

block-chaining: 'cbc
init-vector: some-binary

Block-chaining can be 'cbc (cypher block chaining) or 'ecb (electronic cook book). 'cbc is the default, more secure and should generally be used. The 'ecb is available for compatibility with other software. Init-vector is the initialization vector for 'cbc mode. The default is a sequence of binary zeroes.

Encrypting/Decrypting Data

Open a 'crypt port for encryption or decryption. Then use

open crypt-port
insert crypt-port some-data
(...possibly more insert calls here...)
update crypt-port
new-data: copy crypt-port
close crypt-port

The data to be inserted has to be a string series (e.g. string or binary). The data copied from the port is always of type binary!.

Update has to be called after the last insert call to flush the output buffer and pad the final data block.

It is possible to copy from the port before all data has been written, e.g.

open crypt-port
insert crypt-port some-data
new-data: copy crypt-port
insert crypt-port some-more-data
append new-data copy crypt-port
...
insert crypt-port even-more-data
update crypt-port
append new-data copy crypt-port
close crypt-port

Please note that because of padding there may not be data to copy after every insert, i.e. after inserting data part of that data may linger in internal block buffers, and the next call to copy does not necessarily contain all the data previously inserted. It is necessary to call update in order to force all inserted data to be padded and encrypted.

Blocking/Padding

Blowfish and Rijndael are block-oriented algorithms. They encrypt data blocks of a fixed size (typically 8 bytes) at a time. Because of that, data has to be padded to the block size for encryption, and the padding has to be removed again after decryption. REBOL currently supports two types of padding:

Most of the time self-describing padding should be used (padding: true). With this setting REBOL adds its own padding in such a way that during decryption REBOL can remove the padding and return the original data. Example:

insert encrypt-port "test"
update encrypt-port
encrypted-data: copy encrypt-port

insert decrypt-port encrypted-data
update decrypt-port
print to-string copy decrypt-port
== "test"

It is also possible to apply custom padding algorithms to the data to be encrypted, before inserting them into crypt ports. This can be useful for interoperability with existing encryption schemes (SSH, SSL etc.) which have their own padding algorithms. In that case set padding to false. The length of decrypted data will always be a multiple of the encryption block size, padded with binary zeroes. Example:

insert encrypt-port "test"
update encrypt-port
encrypted-data: copy encrypt-port

insert decrypt-port encrypted-data
update decrypt-port
print to-string copy decrypt-port
== "test^@^@^@^@"

Examples

Creating a pseudo-random 128-bit encryption key

crypt-key: copy/part checksum/secure mold now/precise 16

Encrypting a file

crypt-port: make port! [
    scheme: 'crypt
    algorithm: 'blowfish
    direction: 'encrypt
    strength: 128
    key: crypt-key
    padding: true
]
open crypt-port
insert crypt-port read/binary %inputfile
update crypt-port
write/binary %outputfile copy crypt-port
close crypt-port

Decrypting a file

crypt-port: make port! [
    scheme: 'crypt
    algorithm: 'blowfish
    direction: 'decrypt
    strength: 128
    key: crypt-key
    padding: true
]
open crypt-port
insert crypt-port read/binary %outputfile
update crypt-port
write/binary %inputfile2 copy crypt-port
close crypt-port

(read/binary %inputfile2) = (read/binary %inputfile)
== true

RSA Public Key Encryption

RSA public key encryption is an asymmetric encryption algorithm. In order to encrypt data an RSA key has to be generated. RSA keys have a "public" and a "private" portion. The "private" key has to be kept secret, the "public" key can be distributed. If data is encrypted with the public key then it needs to be decrypted with the private key, and vice versa. This leads to two modes of operation:

EncryptionUse the public key to encrypt, and the private key to decrypt. Anyone can encrypt data, but only the owner of the private key can decrypt it.
SigningUse the private key to encrypt, and the public key to decrypt. The public key decryption is used as a verification that the private key was used for encryption, i.e. if the public key decryption succeeds then this is proof that the person encrypting the data had access to the private key (electronic signature).

RSA is significantly slower than symmetric key encryption algorithms, and a single encryption or decryption operation can only process an amount of data up to the size of the RSA key. For encrypting or decrypting large amounts of data RSA is usually used in combination with symmetric key algorithms or secure checksums as follows:

EncryptionGenerate a random session key. Use symmetric key encryption to encrypt the payload with the session key. RSA-encrypt the session key with the public RSA key. Send the encrypted payload and the encrypted session key to the recipient.
SigningUse checksum/secure to create a cryptographically secure checksum of the data. RSA-encrypt the checksum with the private RSA key. Send the data and the encrypted checksum to the recipient.

Functions

rsa-make-key

This function returns an empty object! laid out as an RSA key. It does not fill in any data. The function is mainly used in preparation for creating an RSA key used for public encryption or decryption.

rsa-generate-key rsa-key size generator

This function creates a new, random RSA key (public and private portion), and fills the data into the object! passed as rsa-key. Size is the number of bits (e.g. 1024). Generator is the prime number used as a generator. The typical value is 3. An RSA key object contains the following fields:

Only the "n" field of a key should be published. The "e" field is usually set to 3 by convention. All other fields have to be kept secret. When saving a private key it is usually most convenient to write the complete molded object to a file, instead of individual fields.

rsa-encrypt rsa-key data /decrypt /private /padding padding-type

This function encrypts or decrypts a binary with an RSA key. The result is another binary. The /decrypt refinement selects decryption (default is encryption). The /private refinement selects encryption or decryption using the private key (default is to use the public key).

The /padding refinement selects the type of padding to use. The default (no /padding refinement) is PKCS1 Type 1 and should be used whenever communication takes place among REBOL scripts only. For compatibility with other environments using RSA the following alternative padding methods are supported:

Examples

Generating a new 1024-bit RSA key

rsa-key: rsa-make-key
rsa-generate-key rsa-key 1024 3

Now rsa-key/n can be distributed as the public key.

Encrypting a text file using RSA

The rsa-pub-key is assumed to contain the RSA public key ('n' value).

rsa-key: rsa-make-key
rsa-key/e: 3
rsa-key/n: rsa-pub-key
crypt-key: copy/part checksum/secure mold now/precise 16
crypt-port: make port! [
    scheme: 'crypt
    algorithm: 'blowfish
    direction: 'encrypt
    strength: 128
    key: crypt-key
    padding: true
]
open crypt-port
insert crypt-port read/binary %inputfile
update crypt-port
crypt-data: copy crypt-port
close crypt-port
crypt-key: rsa-encrypt rsa-key crypt-key

At this time crypt-key and crypt-data have to be sent to the recipient.

Decrypting a text file using RSA

The rsa-key is assumed to be set to the RSA private key generated earlier. The crypt-key and crypt-data have been received from the sender.

crypt-key: rsa-encrypt/private/decrypt rsa-key crypt-key
crypt-port: make port! [
    scheme: 'crypt
    algorithm: 'blowfish
    direction: 'decrypt
    strength: 128
    key: crypt-key
    padding: true
]
open crypt-port
insert crypt-port crypt-data
update crypt-port
write/binary %outputfile copy crypt-port
close crypt-port

At this the contents of outputfile are identical to the contents of inputfile at the sender.

Signing a text file using RSA

The rsa-key is assumed to be set to the RSA private key generated earlier.

signature: rsa-encrypt/private rsa-key checksum/secure read %inputfile

At this time signature has to be sent to the recipient, along with the contents of %inputfile.

Verifying a signature using RSA

The rsa-pub-key is assumed to contain the RSA public key ('n' value). signature contains the signature, and %inputfile the data the signature applies to.

rsa-key: rsa-make-key
rsa-key/e: 3
rsa-key/n: rsa-pub-key
valid-signature?: all [
    not error? try [cksum: rsa-encrypt/decrypt rsa-key signature]
    cksum = checksum/secure read %inputfile
]

DSA Digital Signatures

DSA is used to electronically sign a document. It is similar in functionality to RSA, except it can only be used for signing, not for encryption, and DSA is usually slower than RSA. Like RSA, DSA uses keys which consist of a public and private portion. The public portion has to be distributed to allow signature verification. The private portion has to be kept secret.

DSA can only sign data up to the size of the DSA key. To sign large amounts of data DSA is usually used in combination with secure checksums. This means use checksum/secure on the data to create a cryptographically secure checksum, then use DSA to sign the checksum, and send the signed checksum to the recipient along with the data.

Functions

dsa-make-key /generate length

This function returns an empty object! laid out as a DSA key. It does not fill in any data. The function is mainly used in preparation for creating a DSA key used for signing or signature verification.

The /generate refinement causes the creation of a new "generation environment". A "generation environment" is a set of three numbers (p, q and g) with certain mathematical properties that is shared among a large group of participants and can be used to create DSA keys of a certain size.

The number set describes a convention, is not secret, and is usually hard-coded into applications. It is not part of any individual secret or public key, but is needed in order to perform secret or public key operations. The following generation environments can be used safely:

384 bits:

p: #{A8942EC56B32B48DCA3350F414707B74D5D390480BB5016C0FE72CDAFDC442BA
     0AF56CC2E8B7AED44A7DB3B25A797428F4E779CCA3C1081B7E7169B364C4323D}
q: #{CE7C81B214412D0E1AB5C75D6B863CAB0A40CD17}
g: #{235F1E4BE5A88C88146D54F3FDE6093A03631A66B3754C05844EF98E9F38B754
     35F39349484DD22B061461E040CA619D4BB416A8DEC655CE11FDE2A1ACE88180}

512 bits:

p: #{DEC53F716DA5EB7A8DD3D77525998DB388702ACD81EEE9E58827EA9CD1CD01AE
     54B5C185982A1F6F29EFEFAE4D5FF91F0F02C5508F5A9A9A508E599413AB1723}
q: #{9BB981CD50EB5C995AE51175B6FA3C5130260A55}
g: #{07F85EC72C6F2D4FC5DBD07A341231407EC461DC7973AEA36D796B3671B59EBE
     FF30FC9828AB278C7A992E00FD4E36E335F2E167E974392A17DA4F6577944141}

1024 bits:

p: #{A9FC81DF8EA328CC03D8D1EC88471B56F71A2CF7523C9D10FC60A5D7335D3B00
     8670CE2C620F1287B406BBEF35D56B2FDFAA0CFC8E02331126AC0BF9EAF6AFB7
     A66DCEEF80B41D5243C70C208F57027544C6733B8D865F9D9B1A04E10584CE1B
     F9DEAD21AF7F6AC75F4B7D39F3771A01665CFC4F17830644096A94A03F383B75}
q: #{FBF92DE23BC5F1CB20F123516B35E4BB2B8290AF}
g: #{37EF72A3BEBD342F1FBBCB001906F97A90BBED38AD06CFE9FEE48F243C48E06D
     ABFED1AE6AA202040D0F8EE612A526F9E1DB6329FD233A27AE5C0440846BB335
     6E3D4E994376384FEA2E5E8764EABF89F87816FAAC4F10BA5F002EC9DD33A667
     DD2466D8D34BF102432934EAA13ECCF60F19C404BBD386C9679311B98478AFBB}

Please note that creating a new generation environment can take a long time, possibly several minutes, depending on the key size.

dsa-generate-key dsa-key

This function creates a new private/public DSA key pair. Before calling this function a dsa-key object! has to be created using dsa-make-key, and the generation environment (p, q and g) has to be filled in. After calling this function pub-key contains the public key and priv-key contains the private key.

dsa-make-signature /sign dsa-key data

This function creates a signature object. Without the "/sign" refinement an empty signature object is created, ready to be filled in with a signature received in a transmission, for the purpose of signature verification. With the "/sign" refinement dsa-make-signature signs the specified data, and stores the signature in the returned signature object. The dsa-key passed in needs to contain the fields p, q, g, pub-key and priv-key.

Signatures contain two fields, r and s. Both fields together form the signature, and have to be sent to the recipient in order to allow verification of the signature.

dsa-verify-signature dsa-key data signature

This function verifies whether the supplied signature is valid for the supplied data and has been generated by the private key corresponding to the supplied dsa-key. The dsa-key has to be a DSA public key with the fields p, q, g and pub-key filled in. The dsa-verify-signature returns true (valid signature) or false (invalid signature).

Examples

All binary literals are taken from the sample "generation environment" shown above.

Generating a new 1024-bit DSA key

dsa-key: dsa-make-key
dsa-key/p: 
    #{A9FC81DF8EA328CC03D8D1EC88471B56F71A2CF7523C9D10FC60A5D7335D3B00
     8670CE2C620F1287B406BBEF35D56B2FDFAA0CFC8E02331126AC0BF9EAF6AFB7
     A66DCEEF80B41D5243C70C208F57027544C6733B8D865F9D9B1A04E10584CE1B
     F9DEAD21AF7F6AC75F4B7D39F3771A01665CFC4F17830644096A94A03F383B75}
dsa-key/q: #{FBF92DE23BC5F1CB20F123516B35E4BB2B8290AF}
dsa-key/g:
    #{37EF72A3BEBD342F1FBBCB001906F97A90BBED38AD06CFE9FEE48F243C48E06D
     ABFED1AE6AA202040D0F8EE612A526F9E1DB6329FD233A27AE5C0440846BB335
     6E3D4E994376384FEA2E5E8764EABF89F87816FAAC4F10BA5F002EC9DD33A667
     DD2466D8D34BF102432934EAA13ECCF60F19C404BBD386C9679311B98478AFBB}
dsa-generate-key dsa-key

Now the dsa-key/pub-key can be distributed as the public key.

Signing a text file using DSA

The dsa-key is assumed to be set to the DSA private key generated earlier.

signature: dsa-make-signature/sign dsa-key checksum/secure read %inputfile

At this time signature/r and signature/s have to be sent to the recipient, along with the contents of %inputfile.

Verifying a signature using DSA

The dsa-pub-key is assumed to contain the DSA public key. signature-s and signature-s contain the 'r' and 's' portions of the signature, respectively, and %inputfile the data the signature applies to.

dsa-key: dsa-make-key
dsa-key/p:
    #{A9FC81DF8EA328CC03D8D1EC88471B56F71A2CF7523C9D10FC60A5D7335D3B00
     8670CE2C620F1287B406BBEF35D56B2FDFAA0CFC8E02331126AC0BF9EAF6AFB7
     A66DCEEF80B41D5243C70C208F57027544C6733B8D865F9D9B1A04E10584CE1B
     F9DEAD21AF7F6AC75F4B7D39F3771A01665CFC4F17830644096A94A03F383B75}
dsa-key/q: #{FBF92DE23BC5F1CB20F123516B35E4BB2B8290AF}
dsa-key/g:
    #{37EF72A3BEBD342F1FBBCB001906F97A90BBED38AD06CFE9FEE48F243C48E06D
     ABFED1AE6AA202040D0F8EE612A526F9E1DB6329FD233A27AE5C0440846BB335
     6E3D4E994376384FEA2E5E8764EABF89F87816FAAC4F10BA5F002EC9DD33A667
     DD2466D8D34BF102432934EAA13ECCF60F19C404BBD386C9679311B98478AFBB}
dsa-key/pub-key: dsa-pub-key
signature: dsa-make-signature
signature/r: signature-r
signature/s: signature-s
valid-signature?: dsa-verify-signature dsa-key 
    checksum/secure read %inputfile signature

DH Diffie Hellman Key Exchange

The Diffie Hellman algorithm is used to negotiate a session key between two computers across an insecure line. An (asymmetric and usually faster) alternative is to use RSA, by having one party pick a random session key, encrypt it with a public key and have the other party decrypt it with the corresponding private key.

DH works as follows: each side creates a DH key object. Each side creates a DH private/public key pair. Each side sends its public key to the other side. Each side computes a session key from its private key and the other side's public key. DH guarantees that both session keys are identical. Those keys can then be used for symmetric key encryption.

Functions

dh-make-key /generate length generator

This function returns an empty object! laid out as a DH key. It does not fill in any data. The function is used in preparation for generating a new DH public/private key pair.

The /generate refinement causes the creation of a new "generation environment". The "generator" argument is part of the generation environment, and usually has the value 2. A "generation environment" is a set of numbers (g, p) with certain mathematical properties that is shared among a large group of participant and can be used to create DH keys of a certain size.

The number set describes a convention, is not secret, and is usually hard-coded into applications. It is not part of any individual DH key, but is needed in order in order to create DH keys and to use DH for exchanging session keys. The following generation environments can be used safely:

384 bits:

g: 2
p: #{A6B3DA18CFA6A9DA375DB8863D8C30E6A6D30078A4B3F0FC7CA480AF0EA6EA63
     4EECD1D90E58E2EE12EA1A83D978D55F}

512 bits:

g: 2
p: #{D4D33F6CDD1B333E8C16130F16965D3D0A1233E45AFB3AA02AB18D31E20910DA
     8ED72AEBAA16BCB2250F0C57A54960D4301A7A628E457AC082CBAA11C559F233}

1024 bits:

g: 2
p: #{B19958A84CBF18FB833081908979DEA42C4BA113C1E40C48820324C19A277AC5
     0B7FFA7184128C169542912A1463FABD50894D13DD7BF8E16B3C8481C43AFDC1
     1E9DF980E47FE9B8502BC2F1D4D9D29FA9FADB7B904B2D912907008FC4448B0A
     417E40C4AEE2CD6D6CD3E8906EA0E5AF4A80F9E5E4790773302A228502B56143}

Please note that creating a new generation environment can take a VERY long time, possibly several minutes or hours, depending on the key size.

dh-generate-key dh-key

This function creates a new DH public/private key pair. Before calling this function a dh-key object! has to be created using dh-make-key, and the generation environment (g, p) has to be filled in. After calling this function pub-key contains the public key and priv-key contains the private key.

dh-compute-key dh-key pub-key

This function computes a session key from a locally generated DH private key object and the pub-key binary received from the peer. It returns the negotiated session key as a binary.

Examples

All binary literals are taken from the sample "generation environment" shown above. Each of the following steps has to be executed on both sides participating in the key exchange.

Generating a new DH session key

dh-key: dh-make-key
dh-key/g: 2
dh-key/p:
    #{B19958A84CBF18FB833081908979DEA42C4BA113C1E40C48820324C19A277AC5
     0B7FFA7184128C169542912A1463FABD50894D13DD7BF8E16B3C8481C43AFDC1
     1E9DF980E47FE9B8502BC2F1D4D9D29FA9FADB7B904B2D912907008FC4448B0A
     417E40C4AEE2CD6D6CD3E8906EA0E5AF4A80F9E5E4790773302A228502B56143}
dh-generate-key dh-key

At this time dh-key/pub-key contains the public portion of the DH session key object and has to be sent to the other side.

Computing the key for symmetric key encryption

The dh-pub-key is assumed to contain the public key received from the other side.

crypt-key: copy/part checksum/secure dh-compute-key
    dh-key dh-pub-key 16

At this time crypt-key contains the 128-bit key for symmetric key encryption. Both sides have calculated the same key.

About | Contact | PrivacyREBOL Technologies 2024