Please enable JavaScript to view this site.

A-Shell Reference

Navigation: Subroutines > CRYPTO

CRYPTO Examples

Scroll Prev Top Next More

Example 1: Symmetric key generation

Here we generate two 128 bit keys, returning the first one in a hex string format, and writing the other in raw binary format to a file. Note in both cases we are using the dst parameter (and not the key parameter) for the returned key. The src, decoding, cipher, and key parameters aren't used. Also note that although hex format for binary keys is convenient for string handling and printing purposes, handling it directly in an X variable would be the most compact (and would also eliminate the possibility of it being accidentally exposed in a subroutine trace).

++include ashinc:crypto.def

 

map1 keybits,b,2,128        ! 128 bit key length

map1 hexkey$,s,32           ! 128 bits = 16 bytes (32 hex chars)

map1 status,f               ! return status

 

! return hex key directly in hexkey$ (dst) param:

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", hexkey$, "hex", &

CRYPF_NONE, CRYPTO_CIPHER_NA,"", keybits

if status = 32 then         ! (expecting 32 hex characters)

    print "key (in hex format):";hexkey$

else

    print "Error: ";status

endif

 

! now generate another, writing it in binary format to file

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", "testkey.bin", "", &

CRYPF_DSTFILE, CRYPTO_CIPHER_NA, "", keybits

if status = 16 then         ! (expecting 16 bytes)

    print "key written to testkey.bin"

else

    print "Error: ";status

endif

 

Note: CRYPTOP_GENKEY provides the same functionality as the openssl rand utility. In fact, the second example (above) is directly equivalent to:

openssl rand 16 > test.key

 

Example 2: Encrypt/decrypt a string using AES-128-ECB

Here we generate a new random key (in raw binary format) and use it to encrypt a string, which is then encoded in base64. (This is a typical approach to encrypting sensitive fields within an XML web service request.) Error checking has been removed to simplify the example.

++include ashinc:crypto.def

 

map1 keybits,b,2,128          ! 128 bit key

map1 symkey,x,16              ! raw symmetric key (128 bits = 16 bytes)

map1 src$,s,50                ! plain text string to encrypt

map1 enc$,s,90                ! encrypted/encoded output

map1 dec$,s,50                ! decrypted string (to test decryption)

map1 status,f                 ! return status

 

! generate key into key var

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", symkey, "", &

CRYPF_NONE, CRYPTO_CIPHER_NA,"", keybits

 

! now use it to encrypt the src$

src$ = "This is a secret"

 

xcall CRYPTO, CRYPTOP_ENCRYPT, status, src$, "", enc$, "base64", &

CRYPF_SRCTEXT, CRYPTO_CIPHER_AES,symkey, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

print "status=";status;" cipher text = ";enc$

 

! now decrypt it to see if we get the original back

! (we'll use out of the encryption as the input of the decryption)

xcall CRYPTO, CRYPTOP_DECRYPT, status, enc$, "base64", dec$, "", &

CRYPF_SRCTEXT, CRYPTO_CIPHER_AES, symkey, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

if dec$ = src$ then

    print "Success: decrypted string matches original!"

else

    print "Error: decrypted string doesn't match original!"

endif

 

Note that the dst parameter here must be large enough to hold the encrypted/encoded message. For block ciphers like AES, the raw encrypted message length will be rounded up to the next multiple of the block (key) size, so for a 50 byte source, the encrypted version could be 64 bytes long. The base64 encoding will increase it further by a ratio of 4/3 (rounded up to next multiple of 4), so we would need 88 bytes to be safe. You can use a dynamic string output variable, but you must pre-initialize it to at least the minimum required size (if in doubt, err on the high side!).

 

Example 3: Encrypt/decrypt a file using AES-128-ECB

This is similar to Example 2 except that we'll use files for the source and destination, and a hex string variable for the key. This will be equivalent to the following openssl command strin1g:

"openssl enc -aes-128-ecb -in msg.dat -out msg.enc -a -e -nosalt -K " + hexkey$

++include ashinc:crypto.def

 

map1 keybits,b,2,128          ! 128 bit key

map1 hexkey$,s,32             ! hex encoded key

map1 status,f                 ! return status

map1 src$,s,50                ! source filespec

map1 dst$,s,50                ! dest filespec

map1 decoding$,s,10           ! source file decoding

map1 encoding$,s,10           ! dest file encoding

map1 cflags,b,4

 

! generate 128 bit key in hex format

xcall CRYPTO, CRYPTOP_GENKEY, status, "", "", hexkey$, "hex", CRYPF_NONE, CRYPTO_CIPHER_NA,"", keybits

 

src$      = "msg.dat"

decoding$ = ""                    ! no decoding of source (treat as raw)

dst$      = "msg.enc"

encoding$ = "base64"              ! encode the dest after encryption

 

cflags = CRYPF_KEYHEX             ! key is in hex format

cflags = cflags or CRYPF_SRCFILE  ! source is a file

cflags = cflags or CRYPF_DSTFILE  ! destination is a file

 

? "encrypting ";src$;" into ";dst$;" ..."

xcall CRYPTO, CRYPTOP_ENCRYPT, status, src$, decoding$, dst$, encoding$, &

    cflags, CRYPTO_CIPHER_AES, hexkey$, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

 

if status >= 0 then

    print status;" bytes output to ";dst$

else

    print "error: ";status

    end

endif

 

! now decrypt it into msg.dec (which should match the original msg.dat)

src$      = "msg.enc"             ! source for decryption is the encrypted file

decoding$ = "base64"              ! pre-decode encrypted file before decryption

dst$      = "msg.dec"             ! decrypted file

encoding$ = ""                    ! no post-decryption encoding

 

? "decrypting ";src$;" into ";dst$; " ..."

xcall CRYPTO, CRYPTOP_DECRYPT, status, src$, decoding$, dst$, encoding$, &

    cflags, CRYPTO_CIPHER_AES, hexkey$, keybits, CRYPTO_MODE_ECB, CRYPTO_PAD_PKCS5

 

if status >= 0 then

    print "Decrypted file (";dst$;") should now match original"

else

    print "error: ";status

endif

 

Note that in this case, it isn't necessary to specify whether the files contain text or binary data. (Treating it as binary is always safe.) Also note that for the decryption, the decoding option must match the encoding for the encryption. (We base64-encoded the encrypted file; so we need to first base64-decode it before decrypting.)

 

Example 4: RSA encrypt/decrypt a string

Here we RSA-encrypt the 16 byte raw symmetric key (generated in Example 2), using a public key stored in the file testpub.pem. This is similar to the openssl rsautl command sequence:

echo $KEY | openssl rsautl -encrypt -inkey tetpub.pem -pubin | openssl enc -base64

Note that the source for this operation may itself be a key (e.g. the symmetric key used to encrypt something else that we want to transmit secretly to the remote side), but from the perspective of the RSA encryption operation, it's just an arbitrary message to encrypt. This technique would apply to RSA public/private key encryption of any message, provided it is no longer than the RSA modulus (typically either 1024 or 2048 bits, i.e. 128/256 bytes).

++include ashinc:crypto.def

 

map1 symkey,x,16              ! raw 128 bit symmetric key (generated in Example 2)

map1 symkey2,x,16             ! (to test decryption)

map1 status,f                 ! return status

map1 dst$,s,346               ! dest string

map1 keyfile$,s,30            ! PEM file (public or private key)

map1 cflags,b,4

 

cflags = CRYPF_KEYFILE            ! key is a file (cryptopub.pem)

cflags = cflags or CRYPF_PUBKEY   ! use the public key

keyfile$ = "testpub.pem"          ! public key file

if lookup(keyfile$)= 0 then

    print keyfile$;" not found!  See doc notes to create"

    end

endif

 

xcall CRYPTO, CRYPTOP_ENCRYPT, status, symkey, "", dst$, "base64", &

    cflags, CRYPTO_CIPHER_RSA, keyfile$

if status >= 0

    print "Encryption success: ";status;" encrypted/encoded bytes output"

else

    print "Encryption error: status=";status

    end

endif

 

 

! now decrypt it into rawkey2 (which should match the original msg.dat)

! (this would normally be done by the remote counterpart)

cflags = cflags and not CRYPF_PUBKEY   ! clear PUB flag (we're using private key here)

keyfile$ = "test.pem"                  ! private key file

 

xcall CRYPTO, CRYPTOP_DECRYPT, status, dst$, "base64", symkey2, "", &

    cflags, CRYPTO_CIPHER_RSA, keyfile$

if status >= 0 and symkey = symkey2 then

    print "Decryption success: decrypted symkey matches the original"

else

    print "Decryption error: status=";status

endif

 

Notes:

The size of the encrypted output for RSA encryption is always the same as the RSA modulus (1024 or 2048 bits), adjusted for the encoding. In this case, since base64 encoding expands the message by 4/3, we need at least 256 * 4/3 bytes (rounded up to next multiple of 4) or 344 bytes to hold the output. We mapped dst$ as 346 here to allow for a trailing null and even size.
The keybits parameter is not used with the RSA cipher
You can generate the test.pem (private key) and testpub.pem (public key) files for this example using openssl as follows:

openssl genrsa -out test.pem 2048

openssl rsa -in test.pem -pubout > testpub.pem

 

Example 5: Encode binary data

Here we encode 16 bytes of binary data as a 32 byte hex string:

++include ashinc:crypto.def

 

map1 xdata

    map2 xdata'bytes(16),b,1

map1 hexdata$,s,32            ! hex encoded key (from example 1)

map1 status,f                 ! return status

map1 x,f

 

for x = 1 to 16               ! generate 16 binary bytes

    xdata'bytes(x) = x

next x

 

! encode it in hex

xcall CRYPTO, CRYPTOP_ENCODE, status, xdata, "", hexdata$, "hex", CRYPF_NONE

? "hex encoded bytes: ";hexdata$