Data Encryption Standard

Revision as of 00:09, 25 September 2018 by Robbie (talk | contribs) (Added D)

Demonstrate the Data Encryption Standard. For a complete description of the algorithm see: The DES Algorithm Illustrated

Data Encryption Standard is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.


Task:

Use the

Key 0e329232ea6d0d73
to encrypt 8787878787878787
and display the result 0000000000000000.

Bonus (optional): add standard padding to match the C#, Java, Modula-2, Kotlin, and Phix entries, so the above encrypted result would instead be 0000000000000000A913F4CB0BD30F97.


C#

<lang csharp>using System; using System.IO; using System.Security.Cryptography;

namespace DES {

   class Program {
       //Taken from https://stackoverflow.com/a/311179
       static string ByteArrayToString(byte[] ba) {
           return BitConverter.ToString(ba).Replace("-", "");
       }
       //Modified from https://stackoverflow.com/q/4100996
       //The passwordBytes parameter must be 8 bytes long
       static byte[] Encrypt(byte[] messageBytes, byte[] passwordBytes) {
           byte[] iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
           // Set encryption settings -- Use password for both key and init. vector
           DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
           ICryptoTransform transform = provider.CreateEncryptor(passwordBytes, iv);
           CryptoStreamMode mode = CryptoStreamMode.Write;
           // Set up streams and encrypt
           MemoryStream memStream = new MemoryStream();
           CryptoStream cryptoStream = new CryptoStream(memStream, transform, mode);
           cryptoStream.Write(messageBytes, 0, messageBytes.Length);
           cryptoStream.FlushFinalBlock();
           // Read the encrypted message from the memory stream
           byte[] encryptedMessageBytes = new byte[memStream.Length];
           memStream.Position = 0;
           memStream.Read(encryptedMessageBytes, 0, encryptedMessageBytes.Length);
           return encryptedMessageBytes;
       }
       //Modified from https://stackoverflow.com/q/4100996
       //The passwordBytes parameter must be 8 bytes long
       static byte[] Decrypt(byte[] encryptedMessageBytes, byte[] passwordBytes) {
           byte[] iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
           // Set encryption settings -- Use password for both key and init. vector
           DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
           ICryptoTransform transform = provider.CreateDecryptor(passwordBytes, iv);
           CryptoStreamMode mode = CryptoStreamMode.Write;
           // Set up streams and decrypt
           MemoryStream memStream = new MemoryStream();
           CryptoStream cryptoStream = new CryptoStream(memStream, transform, mode);
           cryptoStream.Write(encryptedMessageBytes, 0, encryptedMessageBytes.Length);
           cryptoStream.FlushFinalBlock();
           // Read decrypted message from memory stream
           byte[] decryptedMessageBytes = new byte[memStream.Length];
           memStream.Position = 0;
           memStream.Read(decryptedMessageBytes, 0, decryptedMessageBytes.Length);
           return decryptedMessageBytes;
       }
       static void Main(string[] args) {
           byte[] keyBytes = new byte[] { 0x0e, 0x32, 0x92, 0x32, 0xea, 0x6d, 0x0d, 0x73 };
           byte[] plainBytes = new byte[] { 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87 };
           byte[] encStr = Encrypt(plainBytes, keyBytes);
           Console.WriteLine("Encoded: {0}", ByteArrayToString(encStr));
           byte[] decBytes = Decrypt(encStr, keyBytes);
           Console.WriteLine("Decoded: {0}", ByteArrayToString(decBytes));
       }
   }

}</lang>

Output:
Encoded: 0000000000000000A913F4CB0BD30F97
Decoded: 8787878787878787

D

Translation of: kotlin

<lang d>import std.array; import std.bitmanip; import std.stdio;

immutable PC1 = [

   57, 49, 41, 33, 25, 17,  9,
    1, 58, 50, 42, 34, 26, 18,
   10,  2, 59, 51, 43, 35, 27,
   19, 11,  3, 60, 52, 44, 36,
   63, 55, 47, 39, 31, 23, 15,
    7, 62, 54, 46, 38, 30, 22,
   14,  6, 61, 53, 45, 37, 29,
   21, 13,  5, 28, 20, 12,  4

];

immutable PC2 = [

   14, 17, 11, 24,  1,  5,
    3, 28, 15,  6, 21, 10,
   23, 19, 12,  4, 26,  8,
   16,  7, 27, 20, 13,  2,
   41, 52, 31, 37, 47, 55,
   30, 40, 51, 45, 33, 48,
   44, 49, 39, 56, 34, 53,
   46, 42, 50, 36, 29, 32

];

immutable IP = [

   58, 50, 42, 34, 26, 18, 10,  2,
   60, 52, 44, 36, 28, 20, 12,  4,
   62, 54, 46, 38, 30, 22, 14,  6,
   64, 56, 48, 40, 32, 24, 16,  8,
   57, 49, 41, 33, 25, 17,  9,  1,
   59, 51, 43, 35, 27, 19, 11,  3,
   61, 53, 45, 37, 29, 21, 13,  5,
   63, 55, 47, 39, 31, 23, 15,  7

];

immutable E = [

   32,  1,  2,  3,  4,  5,
    4,  5,  6,  7,  8,  9,
    8,  9, 10, 11, 12, 13,
   12, 13, 14, 15, 16, 17,
   16, 17, 18, 19, 20, 21,
   20, 21, 22, 23, 24, 25,
   24, 25, 26, 27, 28, 29,
   28, 29, 30, 31, 32,  1

];

immutable S = [

   [
       14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
        0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
        4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
       15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
   ],
   [
       15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
        3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
        0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
       13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9
   ],
   [
       10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
       13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
       13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
        1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12
   ],
   [
        7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
       13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
       10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
        3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
   ],
   [
        2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
       14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
        4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
       11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
   ],
   [
       12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
       10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
        9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
        4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
   ],
   [
        4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
       13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
        1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
        6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
   ],
   [
       13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
        1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
        7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
        2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
   ]

];

immutable P = [

   16,  7, 20, 21,
   29, 12, 28, 17,
    1, 15, 23, 26,
    5, 18, 31, 10,
    2,  8, 24, 14,
   32, 27,  3,  9,
   19, 13, 30,  6,
   22, 11,  4, 25

];

immutable IP2 = [

   40,  8, 48, 16, 56, 24, 64, 32,
   39,  7, 47, 15, 55, 23, 63, 31,
   38,  6, 46, 14, 54, 22, 62, 30,
   37,  5, 45, 13, 53, 21, 61, 29,
   36,  4, 44, 12, 52, 20, 60, 28,
   35,  3, 43, 11, 51, 19, 59, 27,
   34,  2, 42, 10, 50, 18, 58, 26,
   33,  1, 41,  9, 49, 17, 57, 25

];

immutable SHIFTS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];

BitArray bitArrayOfSize(uint count) {

   bool[] buffer = new bool[count];
   return BitArray(buffer);

}

ubyte[] encrypt(const ubyte[] key, const ubyte[] message) in {

   assert(key.length == 8, "Incorrect key size");

} body {

   BitArray[] ks = getSubKeys(key);
   ubyte[] m = message.dup;
   // pad the message so there are 8 byte groups
   ubyte padByte = 8 - m.length % 8;
   foreach (_; 0..padByte) {
       m ~= padByte;
   }
   assert(m.length % 8 == 0);
   ubyte[] sb;
   foreach (i; 0..m.length / 8) {
       auto j = i * 8;
       auto enc = processMessage(m[j..j+8], ks);
       sb ~= enc;
   }
   return sb;

}

/* any padding is assumed to be in the form of trailing zeros following 0DOA;

  only the zeros will be removed */

ubyte[] decrypt(const ubyte[] key, const ubyte[] encoded) in {

   assert(key.length == 8, "Incorrect key size");

} body {

   BitArray[] ks = getSubKeys(key);
   // reverse the subkeys
   foreach (i; 1..9) {
       auto temp = ks[i];
       ks[i] = ks[17 - i];
       ks[17 - i] = temp;
   }
   ubyte[] decoded;
   foreach (i; 0..encoded.length / 8) {
       auto j = i * 8;
       auto dec = processMessage(encoded[j..j+8], ks);
       decoded ~= dec;
   }
   // remove the padding bytes from the decoded message
   ubyte padByte = decoded[$ - 1];
   decoded.length -= padByte;
   return decoded;

}

private BitArray[] getSubKeys(const ubyte[] key) in {

   assert(key.length == 8);

} body {

   auto k = key.toBitArray();
   // permute 'key' using table PC1
   auto kp = bitArrayOfSize(56);
   foreach (i; 0..56) {
       kp[i] = k[PC1[i] - 1];
   }
   // split 'kp' in half and process the resulting series of 'c' and 'd'
   BitArray[] c;
   foreach (_; 0..18) {
       c ~= bitArrayOfSize(56);
   }
   BitArray[] d;
   foreach (_; 0..18) {
       d ~= bitArrayOfSize(28);
   }
   foreach (i; 0..28) {
       c[0][i] = kp[i];
   }
   foreach (i; 0..28) {
       d[0][i] = kp[i + 28];
   }
   foreach (i; 1..17) {
       c[i - 1].shiftLeft(SHIFTS[i - 1], 28, c[i]);
       d[i - 1].shiftLeft(SHIFTS[i - 1], 28, d[i]);
   }
   // merge 'd' into 'c'
   foreach (i; 1..17) {
       foreach (j; 28..56) {
           c[i][j] = d[i][j - 28];
       }
   }
   // form the sub-keys and store them in 'ks'
   BitArray[] ks;
   foreach (_; 0..17) {
       ks ~= bitArrayOfSize(48);
   }
   // permute 'c' using table PC2
   foreach (i; 1..17) {
       foreach (j; 0..48) {
           ks[i][j] = c[i][PC2[j] - 1];
       }
   }
   return ks;

}

private ubyte[] processMessage(const ubyte[] message, BitArray[] ks) {

   auto m = message.toBitArray();
   // permute 'message' using table IP
   auto mp = bitArrayOfSize(64);
   foreach (i; 0..64) {
       mp[i] = m[IP[i] - 1];
   }
   // split 'mp' in half and process the resulting series of 'l' and 'r
   BitArray[] left;
   BitArray[] right;
   foreach (_; 0..17) {
       left ~= bitArrayOfSize(32);
       right ~= bitArrayOfSize(32);
   }
   foreach (i; 0..32) {
       left[0][i] = mp[i];
   }
   foreach (i; 0..32) {
       right[0][i] = mp[i + 32];
   }
   foreach (i; 1..17) {
       left[i] = right[i - 1];
       auto fs = f(right[i - 1], ks[i]);
       left[i - 1] ^= fs;
       right[i] = left[i - 1];
   }
   // amalgamate r[16] and l[16] (in that order) into 'e'
   auto e = bitArrayOfSize(64);
   foreach (i; 0..32) {
       e[i] = right[16][i];
   }
   foreach (i; 32..64) {
       e[i] = left[16][i - 32];
   }
   // permute 'e' using table IP2 ad return result as a hex string
   auto ep = bitArrayOfSize(64);
   foreach (i; 0..64) {
       ep[i] = e[IP2[i] - 1];
   }
   return ep.toByteArray();

}

private BitArray toBitArray(const ubyte[] byteArr) {

   auto bitArr = bitArrayOfSize(8 * byteArr.length);
   for (int i=0; i<byteArr.length; i++) {
       bitArr[8*i+0] = (byteArr[i] & 128) != 0;
       bitArr[8*i+1] = (byteArr[i] & 64) != 0;
       bitArr[8*i+2] = (byteArr[i] & 32) != 0;
       bitArr[8*i+3] = (byteArr[i] & 16) != 0;
       bitArr[8*i+4] = (byteArr[i] & 8) != 0;
       bitArr[8*i+5] = (byteArr[i] & 4) != 0;
       bitArr[8*i+6] = (byteArr[i] & 2) != 0;
       bitArr[8*i+7] = (byteArr[i] & 1) != 0;
   }
   return bitArr;

}

ubyte[] toByteArray(const ref BitArray bitArr) {

   auto len = bitArr.length / 8;
   ubyte[] byteArr = new ubyte[len];
   foreach (i; 0..len) {
       byteArr[i]  = bitArr[8 * i + 0] << 7;
       byteArr[i] |= bitArr[8 * i + 1] << 6;
       byteArr[i] |= bitArr[8 * i + 2] << 5;
       byteArr[i] |= bitArr[8 * i + 3] << 4;
       byteArr[i] |= bitArr[8 * i + 4] << 3;
       byteArr[i] |= bitArr[8 * i + 5] << 2;
       byteArr[i] |= bitArr[8 * i + 6] << 1;
       byteArr[i] |= bitArr[8 * i + 7] << 0;
   }
   return byteArr;

}

void shiftLeft(const ref BitArray self, int times, int len, ref BitArray output) {

   for (int i=0; i<=len; i++) {
       output[i] = self[i];
   }
   for (int t=1; t<=times; t++) {
       auto temp = output[0];
       for (int i=1; i<=len; i++) {
           output[i - 1] = output[i];
       }
       output[len - 1] = temp;
   }

}

private BitArray f(const ref BitArray r, const ref BitArray ks) {

   // permute 'r' using table E
   auto er = bitArrayOfSize(48);
   foreach (i; 0..48) {
       er[i] = r[E[i] - 1];
   }
   // xor 'er' with 'ks' and store back into 'er'
   er ^= ks;
   // process 'er' six bits at a time and store resulting four bits in 'sr'
   auto sr = bitArrayOfSize(32);
   foreach (i; 0..8) {
       auto j = i * 6;
       auto b = new int[6];
       foreach (k; 0..6) {
           b[k] = (er[j+k] != 0) ? 1 : 0;
       }
       auto row = 2 * b[0] + b[5];
       auto col = 8 * b[1] + 4 * b[2] + 2 * b[3] + b[4];
       int m = S[i][row * 16 + col];   // apply table s
       int n = 1;
       while (m > 0) {
           auto p = m % 2;
           sr[(i + 1) * 4 - n] = (p == 1);
           m /= 2;
           n++;
       }
   }
   // permute sr using table P
   auto sp = bitArrayOfSize(32);
   foreach (i; 0..32) {
       sp[i] = sr[P[i] - 1];
   }
   return sp;

}

void main() {

   immutable ubyte[][] keys = [
       [cast(ubyte)0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1],
       [0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
       [0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
   ];
   immutable ubyte[][] messages = [
       [cast(ubyte)0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF],
       [0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87],
       [0x59, 0x6F, 0x75, 0x72, 0x20, 0x6C, 0x69, 0x70, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x6D, 0x6F, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x76, 0x61, 0x73, 0x65, 0x6C, 0x69, 0x6E, 0x65, 0x0D, 0x0A],
   ];
   assert(keys.length == messages.length);
   foreach (i; 0..messages.length) {
       writefln("Key     : %(%02X%)", keys[i]);
       writefln("Message : %(%02X%)", messages[i]);
       ubyte[] encoded = encrypt(keys[i], messages[i]);
       writefln("Encoded : %(%02X%)", encoded);
       ubyte[] decoded = decrypt(keys[i], encoded);
       writefln("Decoded : %(%02X%)", decoded);
       writeln;
   }

}</lang>

Output:
Key     : 133457799BBCDFF1
Message : 0123456789ABCDEF
Encoded : 85E813540F0AB405FDF2E174492922F8
Decoded : 0123456789ABCDEF

Key     : 0E329232EA6D0D73
Message : 8787878787878787
Encoded : 0000000000000000A913F4CB0BD30F97
Decoded : 8787878787878787

Key     : 0E329232EA6D0D73
Message : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A
Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
Decoded : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A

Go

Library solution: <lang go>package main

import (

   "crypto/des"
   "encoding/hex"
   "fmt"
   "log"

)

func main() {

   key, err := hex.DecodeString("0e329232ea6d0d73")
   if err != nil {
       log.Fatal(err)
   }
   c, err := des.NewCipher(key)
   if err != nil {
       log.Fatal(err)
   }
   src, err := hex.DecodeString("8787878787878787")
   if err != nil {
       log.Fatal(err)
   }
   dst := make([]byte, des.BlockSize)
   c.Encrypt(dst, src)
   fmt.Printf("%x\n", dst)

}</lang>

Output:
0000000000000000

Java

Translation of: Kotlin

<lang Java>import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec;

public class DataEncryptionStandard {

   private static byte[] toHexByteArray(String self) {
       byte[] bytes = new byte[self.length() / 2];
       for (int i = 0; i < bytes.length; ++i) {
           bytes[i] = ((byte) Integer.parseInt(self.substring(i * 2, i * 2 + 2), 16));
       }
       return bytes;
   }
   private static void printHexBytes(byte[] self, String label) {
       System.out.printf("%s: ", label);
       for (byte b : self) {
           int bb = (b >= 0) ? ((int) b) : b + 256;
           String ts = Integer.toString(bb, 16);
           if (ts.length() < 2) {
               ts = "0" + ts;
           }
           System.out.print(ts);
       }
       System.out.println();
   }
   public static void main(String[] args) throws Exception {
       String strKey = "0e329232ea6d0d73";
       byte[] keyBytes = toHexByteArray(strKey);
       SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
       Cipher encCipher = Cipher.getInstance("DES");
       encCipher.init(Cipher.ENCRYPT_MODE, key);
       String strPlain = "8787878787878787";
       byte[] plainBytes = toHexByteArray(strPlain);
       byte[] encBytes = encCipher.doFinal(plainBytes);
       printHexBytes(encBytes, "Encoded");
       Cipher decCipher = Cipher.getInstance("DES");
       decCipher.init(Cipher.DECRYPT_MODE, key);
       byte[] decBytes = decCipher.doFinal(encBytes);
       printHexBytes(decBytes, "Decoded");
   }

}</lang>

Output:
Encoded: 0000000000000000a913f4cb0bd30f97
Decoded: 8787878787878787

Kotlin

Version 1 (using library functions)

Presumably, one can use library functions to demonstrate DES as it would be very tedious to implement it from scratch: <lang scala>// version 1.1.3

import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec

fun String.toHexByteArray(): ByteArray {

   val bytes = ByteArray(this.length / 2)
   for (i in 0 until bytes.size) {
       bytes[i] = this.substring(i * 2, i * 2 + 2).toInt(16).toByte()       
   }
   return bytes

}

fun ByteArray.printHexBytes(label: String) {

   print("$label: ")
   for (b in this) {
       val bb = if (b >= 0) b.toInt() else b + 256
       print(bb.toString(16).padStart(2, '0'))
   }
   println()

}

fun main(args: Array<String>) {

   val strKey = "0e329232ea6d0d73"
   val keyBytes = strKey.toHexByteArray()
   val key = SecretKeySpec(keyBytes, "DES") 
   val encCipher = Cipher.getInstance("DES")      
   encCipher.init(Cipher.ENCRYPT_MODE, key)    
   val strPlain = "8787878787878787"
   val plainBytes = strPlain.toHexByteArray()
   val encBytes = encCipher.doFinal(plainBytes)
   encBytes.printHexBytes("Encoded")
   val decCipher = Cipher.getInstance("DES")
   decCipher.init(Cipher.DECRYPT_MODE, key)
   val decBytes = decCipher.doFinal(encBytes)
   decBytes.printHexBytes("Decoded")

}</lang>

Output:

Note that the 'encoded' output includes 8 bytes of padding using the default JVM DES implementation:

Encoded: 0000000000000000a913f4cb0bd30f97
Decoded: 8787878787878787

Version 2 (from scratch)

It wasn't as tedious as I expected due to the admirably clear article linked to above: <lang scala>// version 1.1.3

import java.util.BitSet

object DES {

   private val PC1 = intArrayOf(
       57, 49, 41, 33, 25, 17, 9,
       1, 58, 50, 42, 34, 26, 18,
       10, 2, 59, 51, 43, 35, 27,
       19, 11, 3, 60, 52, 44, 36,
       63, 55, 47, 39, 31, 23, 15,
       7, 62, 54, 46, 38, 30, 22,
       14, 6, 61, 53, 45, 37, 29,
       21, 13, 5, 28, 20, 12, 4
   )
   private val PC2 = intArrayOf(
       14, 17, 11, 24, 1, 5,
       3, 28, 15, 6, 21, 10,
       23, 19, 12, 4, 26, 8,
       16, 7, 27, 20, 13, 2,
       41, 52, 31, 37, 47, 55,
       30, 40, 51, 45, 33, 48,
       44, 49, 39, 56, 34, 53,
       46, 42, 50, 36, 29, 32
   )
   private val IP = intArrayOf(
       58, 50, 42, 34, 26, 18, 10, 2,
       60, 52, 44, 36, 28, 20, 12, 4,
       62, 54, 46, 38, 30, 22, 14, 6,
       64, 56, 48, 40, 32, 24, 16, 8,
       57, 49, 41, 33, 25, 17, 9, 1,
       59, 51, 43, 35, 27, 19, 11, 3,
       61, 53, 45, 37, 29, 21, 13, 5,
       63, 55, 47, 39, 31, 23, 15, 7
   )
   private val E = intArrayOf(
       32, 1, 2, 3, 4, 5,
       4, 5, 6, 7, 8, 9,
       8, 9, 10, 11, 12, 13,
       12, 13, 14, 15, 16, 17,
       16, 17, 18, 19, 20, 21,
       20, 21, 22, 23, 24, 25,
       24, 25, 26, 27, 28, 29,
       28, 29, 30, 31, 32, 1
   )
   private val S = arrayOf(
       intArrayOf(
           14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
           0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
           4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
           15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
       ),
       intArrayOf(
           15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
           3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
           0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
           13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
       ),
       intArrayOf(
           10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
           13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
           13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
           1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
       ),
       intArrayOf(
           7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
           13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
           10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
           3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
       ),
       intArrayOf(
           2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
           14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
           4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
           11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
       ),
       intArrayOf(
           12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
           10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
           9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
           4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
       ),
       intArrayOf(
           4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
           13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
           1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
           6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
       ),
       intArrayOf(
           13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
           1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
           7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
           2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
       )
   )
   private val P = intArrayOf(
       16, 7, 20, 21,
       29, 12, 28, 17,
       1, 15, 23, 26,
       5, 18, 31, 10,
       2, 8, 24, 14,
       32, 27, 3, 9,
       19, 13, 30, 6,
       22, 11, 4, 25
   )
   private val IP2 = intArrayOf(
       40, 8, 48, 16, 56, 24, 64, 32,
       39, 7, 47, 15, 55, 23, 63, 31,
       38, 6, 46, 14, 54, 22, 62, 30,
       37, 5, 45, 13, 53, 21, 61, 29,
       36, 4, 44, 12, 52, 20, 60, 28,
       35, 3, 43, 11, 51, 19, 59, 27,
       34, 2, 42, 10, 50, 18, 58, 26,
       33, 1, 41, 9, 49, 17, 57, 25
   )
   private val SHIFTS = intArrayOf(1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1)
   fun encrypt(key: String, message: String): String {
       val ks = getSubKeys(key)
       var m = message
       val r = m.length % 16 // check if multiple of 16 hex digits
       val rem = 8 - r / 2
       val remStr = "%02X".format(rem)
       for (i in 1..rem) {
           m += remStr
       }
       assert(m.length % 16 == 0)
       val sb = StringBuilder()
       for (i in 0 until m.length / 16) {
           val j = i * 16
           val enc = processMessage(m.substring(j, j + 16), ks)
           sb.append(enc)
       }
       return sb.toString()
   }
   fun decrypt(key: String, encoded: String): String {
       val ks = getSubKeys(key)
       // reverse the subkeys
       for (i in 1..8) {
           val temp = ks[i]
           ks[i] = ks[17 - i]
           ks[17 - i] = temp
       }
       val sb = StringBuilder()
       for (i in 0 until encoded.length / 16) {
           val j = i * 16
           val dec = processMessage(encoded.substring(j, j + 16), ks)
           sb.append(dec)
       }
       //remove the padding
       val padByte = sb[sb.length - 1] - '0'
       return sb.substring(0, sb.length - 2 * padByte)
   }
   private fun getSubKeys(key: String): Array<BitSet> {
       val k = key.toLittleEndianBitSet()
       // permute 'key' using table PC1
       val kp = BitSet(56)
       for (i in 0..55) kp[i] = k[PC1[i] - 1]
       // split 'kp' in half and process the resulting series of 'c' and 'd'
       val c = Array(17) { BitSet(56) }
       val d = Array(17) { BitSet(28) }
       for (i in 0..27) c[0][i] = kp[i]
       for (i in 0..27) d[0][i] = kp[i + 28]
       for (i in 1..16) {
           c[i - 1].shiftLeft(SHIFTS[i - 1], 28, c[i])
           d[i - 1].shiftLeft(SHIFTS[i - 1], 28, d[i])
       }
       // merge 'd' into 'c'
       for (i in 1..16) {
           for (j in 28..55) c[i][j] = d[i][j - 28]
       }
       // form the sub-keys and store them in 'ks'
       val ks = Array(17) { BitSet(48) }
       // permute 'c' using table PC2
       for (i in 1..16) {
           for (j in 0..47) ks[i][j] = c[i][PC2[j] - 1]
       }
       return ks
   }
   private fun processMessage(message: String, ks: Array<BitSet>): String {
       val m = message.toLittleEndianBitSet()
       // permute 'message' using table IP
       val mp = BitSet(64)
       for (i in 0..63) {
           mp[i] = m[IP[i] - 1]
       }
       // split 'mp' in half and process the resulting series of 'l' and 'r
       val l = Array(17) { BitSet(32) }
       val r = Array(17) { BitSet(32) }
       for (i in 0..31) l[0][i] = mp[i]
       for (i in 0..31) r[0][i] = mp[i + 32]
       for (i in 1..16) {
           l[i] = r[i - 1]
           val fs = f(r[i - 1], ks[i])
           l[i - 1].xor(fs)
           r[i] = l[i - 1]
       }
       // amalgamate r[16] and l[16] (in that order) into 'e'
       val e = BitSet(64)
       for (i in 0..31) e[i] = r[16][i]
       for (i in 32..63) e[i] = l[16][i - 32]
       // permute 'e' using table IP2 ad return result as a hex string
       val ep = BitSet(64)
       for (i in 0..63) ep[i] = e[IP2[i] - 1]
       return ep.toHexString(64)
   }
   /* assumes a hex string receiver */
   private fun String.toLittleEndianBitSet(): BitSet {
       val bs = BitSet(this.length * 4)
       for ((i, c) in this.withIndex()) {
           val s = c.toString().toByte(16).toString(2).padStart(4, '0')
           for (j in 0..3) bs[i * 4 + j] = (s[j] == '1')
       }
       return bs
   }
   /* assumes a little-endian bitset receiver */
   private fun BitSet.toHexString(len: Int): String {
       val size = len / 4
       val sb = StringBuilder(size)
       val ba = ByteArray(4)
       for (i in 0 until size) {
           for (j in 0..3) ba[j] = if (this[i * 4 + j]) 1 else 0
           val c = "%X".format(ba[0] * 8 + ba[1] * 4 + ba[2] * 2 + ba[3])
           sb.append(c)
       }
       return sb.toString()
   }
   private fun BitSet.shiftLeft(times: Int, len: Int, out: BitSet) {
       for (i in 0 until len) out[i] = this[i]
       for (t in 1..times) {
           val temp = out[0]
           for (i in 1 until len) out[i - 1] = out[i]
           out[len - 1] = temp
       }
   }
   private fun f(r: BitSet, ks: BitSet): BitSet {
       // permute 'r' using table E
       val er = BitSet(48)
       for (i in 0..47) er[i] = r[E[i] - 1]
       // xor 'er' with 'ks' and store back into 'er'
       er.xor(ks)
       // process 'er' six bits at a time and store resulting four bits in 'sr'
       val sr = BitSet(32)
       for (i in 0..7) {
           val j = i * 6
           val b = IntArray(6)
           for (k in 0..5) b[k] = if (er[j + k]) 1 else 0
           val row = 2 * b[0] + b[5]
           val col = 8 * b[1] + 4 * b[2] + 2 * b[3] + b[4]
           var m = S[i][row * 16 + col]   // apply table S
           var n = 1
           while (m > 0) {
               val p = m % 2
               sr[(i + 1) * 4 - n] = (p == 1)
               m /= 2
               n++
           }
       }
       // permute sr using table P
       val sp = BitSet(32)
       for (i in 0..31) sp[i] = sr[P[i] - 1]
       return sp
   }

}

fun main(args: Array<String>) {

   val keys = listOf("133457799BBCDFF1", "0E329232EA6D0D73", "0E329232EA6D0D73")
   val messages = listOf(
       "0123456789ABCDEF",
       "8787878787878787",
       "596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A"
   )
   for (i in 0..2) {
       println("Key     : ${keys[i]}")
       println("Message : ${messages[i]}")
       val encoded = DES.encrypt(keys[i], messages[i])
       println("Encoded : $encoded")
       val decoded = DES.decrypt(keys[i], encoded)
       println("Decoded : $decoded")
       println()
   }

}</lang>

Output:
Key     : 133457799BBCDFF1
Message : 0123456789ABCDEF
Encoded : 85E813540F0AB405FDF2E174492922F8
Decoded : 0123456789ABCDEF

Key     : 0E329232EA6D0D73
Message : 8787878787878787
Encoded : 0000000000000000A913F4CB0BD30F97
Decoded : 8787878787878787

Key     : 0E329232EA6D0D73
Message : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A
Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
Decoded : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A

Modula-2

<lang modula2>MODULE DataEncryptionStandard; FROM SYSTEM IMPORT BYTE,ADR; FROM DES IMPORT DES,Key1,Create,Destroy,EncryptECB,DecryptECB; FROM FormatString IMPORT FormatString; FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

PROCEDURE PrintHexBytes(str : ARRAY OF BYTE; limit : INTEGER); VAR

   buf : ARRAY[0..7] OF CHAR;
   i,v : INTEGER;

BEGIN

   i := 0;
   WHILE i<limit DO
       v := ORD(str[i]);
       IF v < 16 THEN
           WriteString("0")
       END;
       FormatString("%h", buf, v);
       WriteString(buf);
       INC(i);
   END

END PrintHexBytes;

TYPE BA = ARRAY[0..15] OF BYTE; VAR

   plain,encrypt : BA;
   key : ARRAY[0..0] OF Key1;
   cipher : DES;

BEGIN

   (* Account for the padding *)
   plain := BA{87H, 87H, 87H, 87H, 87H, 87H, 87H, 87H, 8, 8, 8, 8, 8, 8, 8, 8};
   key[0] := Key1{0EH, 32H, 92H, 32H, 0EAH, 6DH, 0DH, 73H};
   cipher := Create(key);
   WriteString("plain:   ");
   PrintHexBytes(plain, 8);
   WriteLn;
   EncryptECB(cipher,ADR(plain),ADR(encrypt),16);
   WriteString("encrypt: ");
   PrintHexBytes(encrypt, 16);
   WriteLn;
   DecryptECB(cipher,ADR(encrypt),ADR(plain),16);
   WriteString("plain:   ");
   PrintHexBytes(plain, 8);
   WriteLn;
   Destroy(cipher);
   ReadChar

END DataEncryptionStandard.</lang>

Output:
plain:   8787878787878787
encrypt: 0000000000000000A913F4CB0BD30F97
plain:   8787878787878787

Phix

Translation of: Kotlin

Implementation following the excellent paper by J. Orlin Grabbe, as linked above. Like Kotlin version 2, this expands values into more manageable bit arrays, which are easier to debug/verify, probably sidestep a few fiddly endian issues, and certainly simplify bit-wise permutations. <lang Phix>-- demo\rosetta\Data_Encryption_Standard.exw constant PC1 = {57, 49, 41, 33, 25, 17, 9,

                1, 58, 50, 42, 34, 26, 18,
               10,  2, 59, 51, 43, 35, 27,
               19, 11,  3, 60, 52, 44, 36,
               63, 55, 47, 39, 31, 23, 15,
                7, 62, 54, 46, 38, 30, 22,
               14,  6, 61, 53, 45, 37, 29,
               21, 13,  5, 28, 20, 12,  4},
               
     SHIFTS = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1},
        PC2 = {14, 17, 11, 24,  1,  5,
                3, 28, 15,  6, 21, 10,
               23, 19, 12,  4, 26,  8,
               16,  7, 27, 20, 13,  2,
               41, 52, 31, 37, 47, 55,
               30, 40, 51, 45, 33, 48,
               44, 49, 39, 56, 34, 53,
               46, 42, 50, 36, 29, 32},
         IP = {58, 50, 42, 34, 26, 18, 10, 2,
               60, 52, 44, 36, 28, 20, 12, 4,
               62, 54, 46, 38, 30, 22, 14, 6,
               64, 56, 48, 40, 32, 24, 16, 8,
               57, 49, 41, 33, 25, 17,  9, 1,
               59, 51, 43, 35, 27, 19, 11, 3,
               61, 53, 45, 37, 29, 21, 13, 5,
               63, 55, 47, 39, 31, 23, 15, 7},
         E = {32,  1,  2,  3,  4,  5,
               4,  5,  6,  7,  8,  9,
               8,  9, 10, 11, 12, 13,
              12, 13, 14, 15, 16, 17,
              16, 17, 18, 19, 20, 21,
              20, 21, 22, 23, 24, 25,
              24, 25, 26, 27, 28, 29,
              28, 29, 30, 31, 32,  1},

         S = {{14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
                0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
                4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
               15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13},
              {15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
                3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
                0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
               13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9},
              {10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
               13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
               13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
                1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12},
              { 7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
               13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
               10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
                3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14},
              { 2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
               14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
                4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
               11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3},
              {12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
               10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
                9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
                4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13},
              { 4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
               13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
                1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
                6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12},
              {13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
                1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
                7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
                2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11}},

        P = {16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
              2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25},
     IP_1 = {40,  8, 48, 16, 56, 24, 64, 32,
             39,  7, 47, 15, 55, 23, 63, 31,
             38,  6, 46, 14, 54, 22, 62, 30,
             37,  5, 45, 13, 53, 21, 61, 29,
             36,  4, 44, 12, 52, 20, 60, 28,
             35,  3, 43, 11, 51, 19, 59, 27,
             34,  2, 42, 10, 50, 18, 58, 26,
             33,  1, 41,  9, 49, 17, 57, 25}

function map64(string s, sequence P)

   if length(s)!=8 then ?9/0 end if -- 64 bits
   string b = "", res = ""
   for i=1 to length(s) do
       b &= sprintf("%08b",s[i])
   end for
   for i=1 to length(P) do
       res &= b[P[i]]-'0'
   end for
   return res

end function

function get_subkeys(string key)

   string kp = map64(key,PC1)
   sequence ks = repeat(repeat('\0',48),16)
   for i=1 to 16 do
       integer shift = SHIFTS[i]
       kp = kp[shift+1..28]&kp[1..shift]&
            kp[shift+29..56]&kp[29..shift+28]
       for j=1 to 48 do ks[i][j] = kp[PC2[j]] end for
   end for
   return ks

end function

function f(sequence r, kn)

   string er = "", sr = "", sp = ""
   for i=1 to 48 do er &= r[E[i]] xor kn[i] end for
   -- process 'er' six bits at a time and store resulting four bits in 'sr'
   for i=1 to 8 do
       integer j = (i-1)*6+1,
               k = sum(sq_mul(er[j..j+5],{32,8,4,2,1,16}))+1
       sr &= sprintf("%04b",S[i][k])
   end for
   for i=1 to 32 do sp &= sr[P[i]]-'0' end for
   return sp

end function

function process_block(string message, sequence k)

   string mp = map64(message,IP),
       {l,r} = {mp[1..32],mp[33..64]}
   for n=1 to 16 do
       {l,r} = {r,sq_xor(l,f(r,k[n]))}
   end for
   string e = r&l, res = ""
   for i=0 to 63 by 8 do
       integer byte = 0
       for bit=1 to 8 do
           byte = byte*2+e[IP_1[i+bit]]
       end for
       res &= byte
   end for
   return res

end function

function des(string key, message, bool decode=false)

   sequence k = get_subkeys(key)
   if decode then
       k = reverse(k)
   else
       -- (match the C#/Java/Modula-2 library implementations, in
       --  case we're swapping messages with something using them)
       integer p = 8-mod(length(message),8)
       for i=1 to p do message &= p end for
   end if
   -- check message is multiple of 8 bytes (= 64 bits)
   if mod(length(message),8)!=0 then ?9/0 end if
   string res = ""
   for i=1 to length(message) by 8 do
       res &= process_block(message[i..i+7], k)
   end for
   if decode then
       -- ditto
       res = res[1..length(res)-res[$]]
   end if
   return res

end function

constant TESTS = {{x"133457799BBCDFF1", x"0123456789ABCDEF", "85E813540F0AB405FDF2E174492922F8"},

                 {x"0E329232EA6D0D73", x"8787878787878787", "0000000000000000A913F4CB0BD30F97"},
                 {x"0E329232EA6D0D73",

-- x"596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A",

                  "Your lips are smoother than vaseline\r\n",
                  "C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99"}}

function as_hex(string s)

   string res = ""
   for i=1 to length(s) do
       res &= sprintf("%02x",s[i])
   end for 
   return res

end function

for i=1 to length(TESTS) do

   string {key,msg,expect} = TESTS[i],
          keytxt = as_hex(key),
          msgtxt = iff(i!=3?as_hex(msg):sprint(msg)),
          encoded = des(key, msg),
          enctxt = as_hex(encoded),
          error = iff(enctxt=expect?"":"\n********* "&expect&" expected"),
          decoded = des(key, encoded, true),
          dectxt = iff(i!=3?as_hex(decoded):sprint(decoded)),
          derror = iff(decoded=msg?"":" *** error")
   printf(1,"Key     : %s\n",{keytxt})
   printf(1,"Message : %s\n",{msgtxt})
   printf(1,"Encoded : %s%s\n",{enctxt,error})
   printf(1,"Decoded : %s%s\n\n",{dectxt,derror})

end for</lang>

Output:
Key     : 133457799BBCDFF1
Message : 0123456789ABCDEF
Encoded : 85E813540F0AB405FDF2E174492922F8
Decoded : 0123456789ABCDEF

Key     : 0E329232EA6D0D73
Message : 8787878787878787
Encoded : 0000000000000000A913F4CB0BD30F97
Decoded : 8787878787878787

Key     : 0E329232EA6D0D73
Message : "Your lips are smoother than vaseline\r\n"
Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
Decoded : "Your lips are smoother than vaseline\r\n"

Python

This example is incorrect. Please fix the code and remove this message.

Details: encrypted should be c099... not ca57...

implemented like in the article linked in description.
really good article btw <lang Python>#!/usr/bin/python

  1. Permutation tables and Sboxes

IP = (

   58, 50, 42, 34, 26, 18, 10, 2,
   60, 52, 44, 36, 28, 20, 12, 4,
   62, 54, 46, 38, 30, 22, 14, 6,
   64, 56, 48, 40, 32, 24, 16, 8,
   57, 49, 41, 33, 25, 17, 9,  1,
   59, 51, 43, 35, 27, 19, 11, 3,
   61, 53, 45, 37, 29, 21, 13, 5,
   63, 55, 47, 39, 31, 23, 15, 7

) IP_INV = (

   40,  8, 48, 16, 56, 24, 64, 32,
   39,  7, 47, 15, 55, 23, 63, 31,
   38,  6, 46, 14, 54, 22, 62, 30,
   37,  5, 45, 13, 53, 21, 61, 29,
   36,  4, 44, 12, 52, 20, 60, 28,
   35,  3, 43, 11, 51, 19, 59, 27,
   34,  2, 42, 10, 50, 18, 58, 26,
   33,  1, 41,  9, 49, 17, 57, 25

) PC1 = (

   57, 49, 41, 33, 25, 17, 9,
   1,  58, 50, 42, 34, 26, 18,
   10, 2,  59, 51, 43, 35, 27,
   19, 11, 3,  60, 52, 44, 36,
   63, 55, 47, 39, 31, 23, 15,
   7,  62, 54, 46, 38, 30, 22,
   14, 6,  61, 53, 45, 37, 29,
   21, 13, 5,  28, 20, 12, 4

) PC2 = (

   14, 17, 11, 24, 1,  5,
   3,  28, 15, 6,  21, 10,
   23, 19, 12, 4,  26, 8,
   16, 7,  27, 20, 13, 2,
   41, 52, 31, 37, 47, 55,
   30, 40, 51, 45, 33, 48,
   44, 49, 39, 56, 34, 53,
   46, 42, 50, 36, 29, 32

)

E = (

   32, 1,  2,  3,  4,  5,
   4,  5,  6,  7,  8,  9,
   8,  9,  10, 11, 12, 13,
   12, 13, 14, 15, 16, 17,
   16, 17, 18, 19, 20, 21,
   20, 21, 22, 23, 24, 25,
   24, 25, 26, 27, 28, 29,
   28, 29, 30, 31, 32, 1

)

Sboxes = {

   0: (
       14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
       0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
       4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
       15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
   ),
   1: (
       15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
       3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
       0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
       13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9 
   ),
   2: (
       10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
       13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
       13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
       1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12 
   ),
   3: (
       7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
       13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
       10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
       3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
   ),
   4: (
       2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
       14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
       4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
       11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
   ),
   5: (
       12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
       10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
       9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
       4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
   ),
   6: (
       4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
       13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
       1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
       6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
   ),
   7: (
       13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
       1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
       7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
       2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
   )

}

P = (

   16,  7, 20, 21,
   29, 12, 28, 17,
   1, 15, 23, 26,
   5, 18, 31, 10,
   2,  8, 24, 14,
   32, 27,  3,  9,
   19, 13, 30,  6,
   22, 11, 4,  25

)

def process_input(msg, key, decrypt=False):

   # only takes int values, not str
   # no need for manual padding during encryption using python ints and bitshifts
   if key.bit_length() > 64:
       return -1
   # split msg into 64-bit blocks
   msg_blocks = []
   if msg.bit_length() > 64:
       while msg.bit_length() > 0:
           block = msg & (2**64-1)
           msg_blocks.append(block)
           msg >>= 64
   else:
       msg_blocks.append(msg)
   # encrypt each block seperately using key (ECB-mode)
   cipher_blocks = []
   for block in msg_blocks:
       if decrypt:
           cipher_block = encrypt(block, key, decrypt=True)
       else:
           cipher_block = encrypt(block, key)
       cipher_blocks.append(cipher_block)
   # concatenate blocks to one int again
   cipher_msg = 0
   for block in cipher_blocks:
       cipher_msg <<= 64
       cipher_msg += block
   return cipher_msg
   

def encrypt(msg, key, decrypt=False):

   # permutate by table PC1
   key = permutation_by_table(key, 64, PC1) # 64bit -> PC1 -> 56bit
   # split up key in two halves
   # generate the 16 round keys
   C0 = key >> 28
   D0 = key & (2**28-1)
   round_keys = generate_round_keys(C0, D0) # 56bit -> PC2 -> 48bit
   msg_block = permutation_by_table(msg, 64, IP)
   L0 = msg_block >> 32
   R0 = msg_block & (2**32-1)
   # apply thr round function 16 times in following scheme (feistel cipher):
   L_last = L0
   R_last = R0
   for i in range(1,17):
       if decrypt: # just use the round keys in reversed order
           i = 17-i
       L_round = R_last
       R_round = L_last ^ round_function(R_last, round_keys[i])
       L_last = L_round
       R_last = R_round
   # concatenate reversed
   cipher_block = (R_round<<32) + L_round
   # final permutation
   cipher_block = permutation_by_table(cipher_block, 64, IP_INV)
   return cipher_block


def round_function(Ri, Ki):

   # expand Ri from 32 to 48 bit using table E
   Ri = permutation_by_table(Ri, 32, E)
   # xor with round key
   Ri ^= Ki
   # split Ri into 8 groups of 6 bit
   Ri_blocks = [((Ri & (0b111111 << shift_val)) >> shift_val) for shift_val in (42,36,30,24,18,12,6,0)]
   # interpret each block as address for the S-boxes
   for i, block in enumerate(Ri_blocks):
       # grab the bits we need
       row = ((0b100000 & block) >> 4) + (0b1 & block)
       col = (0b011110 & block) >> 1
       # sboxes are stored as one-dimensional tuple, so we need to calc the index this way
       Ri_blocks[i] = Sboxes[i][16*row+col]
   # pack the blocks together again by concatenating
   Ri_blocks = zip(Ri_blocks, (28,24,20,16,12,8,4,0))
   Ri = 0
   for block, lshift_val in Ri_blocks:
       Ri += (block << lshift_val)
   # another permutation 32bit -> 32bit
   Ri = permutation_by_table(Ri, 32, P)
   return Ri

def permutation_by_table(block, block_len, table):

   # quick and dirty casting to str
   block_str = bin(block)[2:].zfill(block_len)
   perm = []
   for pos in range(len(table)):
       perm.append(block_str[table[pos]-1])
   return int(.join(perm), 2)

def generate_round_keys(C0, D0):

   # returns dict of 16 keys (one for each round)
   round_keys = dict.fromkeys(range(0,17))
   lrot_values = (1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1)
   # left-rotation function
   lrot = lambda val, r_bits, max_bits: \
   (val << r_bits%max_bits) & (2**max_bits-1) | \
   ((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
   # initial rotation
   C0 = lrot(C0, 0, 28)
   D0 = lrot(D0, 0, 28)
   round_keys[0] = (C0, D0)
   # create 16 more different key pairs
   for i, rot_val in enumerate(lrot_values):
       i+=1
       Ci = lrot(round_keys[i-1][0], rot_val, 28)
       Di = lrot(round_keys[i-1][1], rot_val, 28)
       round_keys[i] = (Ci, Di)
   # round_keys[1] for first round
   #           [16] for 16th round
   # dont need round_keys[0] anymore, remove
   del round_keys[0]
   # now form the keys from concatenated CiDi 1<=i<=16 and by apllying PC2
   for i, (Ci, Di) in round_keys.items():
       Ki = (Ci << 28) + Di
       round_keys[i] = permutation_by_table(Ki, 56, PC2) # 56bit -> 48bit
   return round_keys

k = 0x0e329232ea6d0d73 # 64 bit m = 0x8787878787878787 m_long = 0x596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A

def prove(key, msg):

   print('key:       {:x}'.format(key))
   print('message:   {:x}'.format(msg))
   cipher_text = process_input(msg, key)
   print('encrypted: {:x}'.format(cipher_text))
   plain_text = process_input(cipher_text, key, decrypt=True)
   print('decrypted: {:x}'.format(plain_text))

prove(k, m) print('----------') prove(k, m_long) </lang>

Output:
key:       e329232ea6d0d73
message:   8787878787878787
encrypted: 0
decrypted: 8787878787878787
----------
key:       e329232ea6d0d73
message:   596f7572206c6970732061726520736d6f6f74686572207468616e20766173656c696e650d0a
encrypted: ca57d5c43d9ab744f2734b6d497cc0ca6c293d78d8ee1cbf51c50571f460c9f1088f68e9d7b9fb4a
decrypted: 596f7572206c6970732061726520736d6f6f74686572207468616e20766173656c696e650d0a

REXX

Implementation of the algorithm desribed in the cited article.
Decryption is now supported as well <lang rexx>Parse Upper Arg action Select

 When action='?' Then Do
   Say "REXX des shows     how '8787878787878787'X is encoded to"
   Say "                       '000000000000000'X"
   Say "REXX des DEC shows how '000000000000000'X is decoded to"
   Say "                       '8787878787878787'X"
   Exit
   End
 When action= | action='ENC' Then
   encode=1
 When action= | action='DEC' Then
   encode=0
 Otherwise Do
   Say 'Invalid argument' action '(must be ENC or DEC or omitted)'
   Exit
   End
 End

o='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.-' Call init Call debug 'tr_pc_1='tr_pc_1 Call debug 'tr_ip ='tr_ip Call debug 'tr_p ='tr_p Call debug 'tr_ipa ='tr_ipa

kx='0e329232ea6d0d73' If encode Then

 mx='8787878787878787'

Else

 mx='0000000000000000'

k=x2b(kx) m=x2b(mx) Say 'Message:' mx Say 'Key  :' kx ka=translate(tr_pc_1,k,o) Call debug 'ka='ka Parse Var ka c.0 +28 d.0 shifts='1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1' Do i=1 To 16

 ip=i-1
 c.i=shift(c.ip,word(shifts,i))
 d.i=shift(d.ip,word(shifts,i))
 End

Do i=1 To 16

 cd.i=c.i||d.i
 k.i=translate(tr_pc_2,cd.i,o)
 Call debug 'k.'i'='k.i
 End

If encode=0 Then Do /*revert the subkeys */

 Do i=1 To 16
   j=17-i
   kd.i=k.j
   End
 Do i=1 To 16
   k.i=kd.i
   End
 End

IP=translate(tr_ip,m,o) Call debug 'ip='ip

Parse Var ip l.0 +32 r.0

Call debug 'E(R.0)='E(R.0) Call debug 'k.1 ='k.1 t=xor(k.1,E(R.0)) Call debug 't ='t Call debug length(t) zz= Do i=1 To 8

 Parse Var t b +6 t
 zz=zz||s(i,b)
 End

Call debug 'zz='zz f=translate(tr_p,zz,o) Call debug 'f='f r.1=xor(l.0,f) Call debug 'r.1='r.1 l.1=r.0 Do j=2 To 16

 ja=j-1
 l.j=r.ja
 z=xor(k.j,e(r.ja))
 zz=
 Do i=1 To 8
   Parse Var z b +6 z
   zz=zz||s(i,b)
   End
 Call debug j zz
 f=translate(tr_p,zz,o)
 Call debug j f
 r.j=xor(l.ja,f)
 End

Call debug 'l.16='l.16 Call debug 'r.16='r.16

zzz=r.16||l.16 c=translate(tr_ipa,zzz,o) Call debug c Say 'Result :' b2x(c) Exit

f: Procedure Expose s. o tr_p

 Parse Arg r,k
 z=xor(k,e(r))
 zz=translate(tr_p,z,o)
 Return zz

init: PC_1='57 49 41 33 25 17 9'-

    ' 1 58 50 42 34 26 18'-
    '10  2 59 51 43 35 27'-
    '19 11  3 60 52 44 36'-
    '63 55 47 39 31 23 15'-
    ' 7 62 54 46 38 30 22'-
    '14  6 61 53 45 37 29'-
    '21 13  5 28 20 12  4'

tr_pc_1= Do i=1 To words(pc_1)

 tr_pc_1=tr_pc_1||substr(o,word(pc_1,i),1)
 End

tr_pc_1=tr_pc_1

kb=translate(tr_pc_1,k,o) kc=strip(kb,,'*')

PC_2='14 17 11 24 1 5',

    ' 3  28  15   6  21  10',
    '23  19  12   4  26   8',
    '16   7  27  20  13   2',
    '41  52  31  37  47  55',
    '30  40  51  45  33  48',
    '44  49  39  56  34  53',
    '46  42  50  36  29  32'

tr_pc_2= Do i=1 To words(pc_2)

 tr_pc_2=tr_pc_2||substr(o,word(pc_2,i),1)
 End

Do i=1 To 16

 cd.i=c.i||d.i
 k.i=translate(ok,cd.i,o)
 Call debug 'k.'i'='k.i
 End

IP='58 50 42 34 26 18 10 2',

  '60 52 44 36 28 20 12  4',
  '62 54 46 38 30 22 14  6',
  '64 56 48 40 32 24 16  8',
  '57 49 41 33 25 17  9  1',
  '59 51 43 35 27 19 11  3',
  '61 53 45 37 29 21 13  5',
  '63 55 47 39 31 23 15  7'

tr_ip= Do i=1 To words(IP)

 tr_ip=tr_ip||substr(o,word(ip,i),1)
 End


P='16 7 20 21',

 '29 12 28 17',
 ' 1 15 23 26',
 ' 5 18 31 10',
 ' 2  8 24 14',
 '32 27  3  9',
 '19 13 30  6',
 '22 11  4 25'

tr_p= Do i=1 To words(p)

 tr_p=tr_p||substr(o,word(p,i),1)
 End

SM.1='14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7',

    ' 0 15   7  4  14  2  13  1  10  6  12 11   9  5   3  8',
    ' 4  1  14  8  13  6   2 11  15 12   9  7   3 10   5  0',
    '15 12   8  2   4  9   1  7   5 11   3 14  10  0   6 13'

SM.2='15 1 8 14 6 11 3 4 9 7 2 13 12 0 5 10',

    ' 3 13   4  7  15  2   8 14  12  0   1 10   6  9  11  5',
    ' 0 14   7 11  10  4  13  1   5  8  12  6   9  3   2 15',
    '13  8  10  1   3 15   4  2  11  6   7 12   0  5  14  9'

SM.3='10 0 9 14 6 3 15 5 1 13 12 7 11 4 2 8',

    '13  7   0  9   3  4   6 10   2  8   5 14  12 11  15  1',
    '13  6   4  9   8 15   3  0  11  1   2 12   5 10  14  7',
    ' 1 10  13  0   6  9   8  7   4 15  14  3  11  5   2 12'

SM.4=' 7 13 14 3 0 6 9 10 1 2 8 5 11 12 4 15',

    '13  8  11  5   6 15   0  3   4  7   2 12   1 10  14  9',
    '10  6   9  0  12 11   7 13  15  1   3 14   5  2   8  4',
    ' 3 15   0  6  10  1  13  8   9  4   5 11  12  7   2 14'

SM.5=' 2 12 4 1 7 10 11 6 8 5 3 15 13 0 14 9',

    '14 11   2 12   4  7  13  1   5  0  15 10   3  9   8  6',
    ' 4  2   1 11  10 13   7  8  15  9  12  5   6  3   0 14',
    '11  8  12  7   1 14   2 13   6 15   0  9  10  4   5  3'

SM.6='12 1 10 15 9 2 6 8 0 13 3 4 14 7 5 11',

    '10 15   4  2   7 12   9  5   6  1  13 14   0 11   3  8',
    ' 9 14  15  5   2  8  12  3   7  0   4 10   1 13  11  6',
    ' 4  3   2 12   9  5  15 10  11 14   1  7   6  0   8 13'

SM.7=' 4 11 2 14 15 0 8 13 3 12 9 7 5 10 6 1',

    '13  0  11  7   4  9   1 10  14  3   5 12   2 15   8  6',
    ' 1  4  11 13  12  3   7 14  10 15   6  8   0  5   9  2',
    ' 6 11  13  8   1  4  10  7   9  5   0 15  14  2   3 12'

SM.8='13 2 8 4 6 15 11 1 10 9 3 14 5 0 12 7',

    ' 1 15  13  8  10  3   7  4  12  5   6 11   0 14   9  2',
    ' 7 11   4  1   9 12  14  2   0  6  10 13  15  3   5  8',
    ' 2  1  14  7   4 10   8 13  15 12   9  0   3  5   6 11'

Do i=1 To 8

 Do r=0 To 3
   Do c=0 To 15
     Parse Var sm.i s.i.r.c sm.i
     End
   End
 End

ipa='40 8 48 16 56 24 64 32',

   '39  7 47 15 55 23 63 31',
   '38  6 46 14 54 22 62 30',
   '37  5 45 13 53 21 61 29',
   '36  4 44 12 52 20 60 28',
   '35  3 43 11 51 19 59 27',
   '34  2 42 10 50 18 58 26',
   '33  1 41  9 49 17 57 25'

tr_ipa= Do i=1 To words(ipa)

 tr_ipa=tr_ipa||substr(o,word(ipa,i),1)
 End

Return

shift: Procedure

 Parse Arg in,s
 out=substr(in,s+1)left(in,s)
 Return out

E: Procedure Parse Arg s esel='32 1 2 3 4 5',

    ' 4  5  6  7  8  9',
    ' 8  9 10 11 12 13',
    '12 13 14 15 16 17',
    '16 17 18 19 20 21',
    '20 21 22 23 24 25',
    '24 25 26 27 28 29',
    '28 29 30 31 32  1'

r= Do i=1 To words(esel)

 r=r||substr(s,word(esel,i),1)
 End

Return r

xor: Procedure Parse Arg u,v r= Do i=1 To length(u)

 cc=substr(u,i,1)substr(v,i,1)
 r=r||(pos(cc,'01 10')>0)
 End

Return r

s: Procedure Expose s.

 Parse Arg i,b
 Parse Var b r1 +1 c +4 r2
 r=r1||r2
 rb=num(r)
 cb=num(c)
 result=s.i.rb.cb
 Return num2bits(result)

num: Procedure

 Parse Arg s
 res=0
 Do i=1 To length(s)
   Parse Var s c +1 s
   res=2*res+c
   End
 Return res

num2bits: Procedure

 Parse Arg n
 nx=d2x(n)
 r=
 Do i=1 To 4
   dig=n//2
   r=dig||r
   n=n%2
   End
 Return r

debug: /* Say arg(1) */ Return</lang>

Output:
I:\>rexx des2
Message: 8787878787878787
Key    : 0e329232ea6d0d73
Result : 0000000000000000

I:\>rexx des2 dec
Message: 0000000000000000
Key    : 0e329232ea6d0d73
Result : 8787878787878787

Scala

<lang Scala>import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec

object DataEncryptionStandard extends App {

 private def toHexByteArray(self: String) = {
   val bytes = new Array[Byte](self.length / 2)
   for (i <- bytes.indices)
     bytes(i) = Integer.parseInt(self.substring(i * 2, i * 2 + 2), 16).toByte
   bytes
 }
 private def printHexBytes(self: Array[Byte], label: String): Unit = {
   printf("%s: ", label)
   for (b <- self) {
     val bb = if (b >= 0) b.toInt else b + 256
     var ts = Integer.toString(bb, 16)
     if (ts.length < 2) ts = "0" + ts
     print(ts)
   }
   println()
 }
 val strKey = "0e329232ea6d0d73"
 val keyBytes = toHexByteArray(strKey)
 val key = new SecretKeySpec(keyBytes, "DES")
 val encCipher = Cipher.getInstance("DES")
 encCipher.init(Cipher.ENCRYPT_MODE, key)
 val strPlain = "8787878787878787"
 val plainBytes = toHexByteArray(strPlain)
 val encBytes = encCipher.doFinal(plainBytes)
 printHexBytes(encBytes, "Encoded")
 val decCipher = Cipher.getInstance("DES")
 decCipher.init(Cipher.DECRYPT_MODE, key)
 val decBytes = decCipher.doFinal(encBytes)
 printHexBytes(decBytes, "Decoded")

}</lang>

Output:

See it running in your browser by Scastie (JVM).

Symsyn

<lang Symsyn>pc1 : 56

: 48
: 40
: 32
: 24
: 16
: 8
: 0
: 57
: 49
: 41
: 33
: 25
: 17
: 9
: 1
: 58
: 50
: 42
: 34
: 26
: 18
: 10
: 2
: 59
: 51
: 43
: 35
: 62
: 54
: 46
: 38
: 30
: 22
: 14
: 6
: 61
: 53
: 45
: 37
: 29
: 21
: 13
: 5
: 60
: 52
: 44
: 36
: 28
: 20
: 12
: 4
: 27
: 19
: 11
: 3

Pc2 : 13

: 16
: 10
: 23
: 0
: 4
: 2
: 27
: 14
: 5
: 20
: 9
: 22
: 18
: 11
: 3
: 25
: 7
: 15
: 6
: 26
: 19
: 12
: 1
: 40
: 51
: 30
: 36
: 46
: 54
: 29
: 39
: 50
: 44
: 32
: 47
: 43
: 48
: 38
: 55
: 33
: 52
: 45
: 41
: 49
: 35
: 28
: 31

P : 15

: 6
: 19
: 20
: 28
: 11
: 27
: 16
: 0
: 14
: 22
: 25
: 4
: 17
: 30
: 9
: 1
: 7
: 23
: 13
: 31
: 26
: 2
: 8
: 18
: 12
: 29
: 5
: 21
: 10
: 3
: 24

Ebit : 31

: 0
: 1
: 2
: 3
: 4
: 3
: 4
: 5
: 6
: 7
: 8
: 7
: 8
: 9
: 10
: 11
: 12
: 11
: 12
: 13
: 14
: 15
: 16
: 15
: 16
: 17
: 18
: 19
: 20
: 19
: 20
: 21
: 22
: 23
: 24
: 23
: 24
: 25
: 26
: 27
: 28
: 27
: 28
: 29
: 30
: 31
: 0

DesIP : 57

: 49
: 41
: 33
: 25
: 17
: 9
: 1
: 59
: 51
: 43
: 35
: 27
: 19
: 11
: 3
: 61
: 53
: 45
: 37
: 29
: 21
: 13
: 5
: 63
: 55
: 47
: 39
: 31
: 23
: 15
: 7
: 56
: 48
: 40
: 32
: 24
: 16
: 8
: 0
: 58
: 50
: 42
: 34
: 26
: 18
: 10
: 2
: 60
: 52
: 44
: 36
: 28
: 20
: 12
: 4
: 62
: 54
: 46
: 38
: 30
: 22
: 14
: 6

DesIPIV : 39

: 7
: 47
: 15
: 55
: 23
: 63
: 31
: 38
: 6
: 46
: 14
: 54
: 22
: 62
: 30
: 37
: 5
: 45
: 13
: 53
: 21
: 61
: 29
: 36
: 4
: 44
: 12
: 52
: 20
: 60
: 28
: 35
: 3
: 43
: 11
: 51
: 19
: 59
: 27
: 34
: 2
: 42
: 10
: 50
: 18
: 58
: 26
: 33
: 1
: 41
: 9
: 49
: 17
: 57
: 25
: 32
: 0
: 40
: 8
: 48
: 16
: 56
: 24

DesS1 : 14

:  0
:  4
:  15
:  13
:  7
:  1
:  4
:  2
:  14
:  15
:  2
:  11
:  13
:  8
:  1
:  3
:  10
:  10
:  6
:  6
:  12
:  12
:  11
:  5
:  9
:  9
:  5
:  0
:  3
:  7
:  8
:  4
:  15
:  1
:  12
:  14
:  8
:  8
:  2
:  13
:  4
:  6
:  9
:  2
:  1
:  11
:  7
:  15
:  5
:  12
:  11
:  9
:  3
:  7
:  14
:  3
:  10
:  10
:  0
:  5
:  6
:  0
:  13

S2 : 15

:  3
:  1
:  13
:  8
:  4
:  14
:  7
:  6
:  15
:  11
:  2
:  3
:  8
:  4
:  14
:  9
:  12
:  7
:  0
:  2
:  1
:  13
:  10
:  12
:  6
:  0
:  9
:  5
:  11
:  10
:  5
:  0
:  13
:  14
:  8
:  7
:  10
:  11
:  1
:  10
:  3
:  4
:  15
:  13
:  4
:  1
:  2
:  5
:  11
:  8
:  6
:  12
:  7
:  6
:  12
:  9
:  0
:  3
:  5
:  2
:  14
:  15
:  9

S3 : 10

:  13
:  0
:  7
:  9
:  0
:  14
:  9
:  6
:  3
:  3
:  4
:  15
:  6
:  5
:  10
:  1
:  2
:  13
:  8
:  12
:  5
:  7
:  14
:  11
:  12
:  4
:  11
:  2
:  15
:  8
:  1
:  13
:  1
:  6
:  10
:  4
:  13
:  9
:  0
:  8
:  6
:  15
:  9
:  3
:  8
:  0
:  7
:  11
:  4
:  1
:  15
:  2
:  14
:  12
:  3
:  5
:  11
:  10
:  5
:  14
:  2
:  7
:  12

S4 : 7

:  13
:  13
:  8
:  14
:  11
:  3
:  5
:  0
:  6
:  6
:  15
:  9
:  0
:  10
:  3
:  1
:  4
:  2
:  7
:  8
:  2
:  5
:  12
:  11
:  1
:  12
:  10
:  4
:  14
:  15
:  9
:  10
:  3
:  6
:  15
:  9
:  0
:  0
:  6
:  12
:  10
:  11
:  1
:  7
:  13
:  13
:  8
:  15
:  9
:  1
:  4
:  3
:  5
:  14
:  11
:  5
:  12
:  2
:  7
:  8
:  2
:  4
:  14

S5 : 2

:  14
:  12
:  11
:  4
:  2
:  1
:  12
:  7
:  4
:  10
:  7
:  11
:  13
:  6
:  1
:  8
:  5
:  5
:  0
:  3
:  15
:  15
:  10
:  13
:  3
:  0
:  9
:  14
:  8
:  9
:  6
:  4
:  11
:  2
:  8
:  1
:  12
:  11
:  7
:  10
:  1
:  13
:  14
:  7
:  2
:  8
:  13
:  15
:  6
:  9
:  15
:  12
:  0
:  5
:  9
:  6
:  10
:  3
:  4
:  0
:  5
:  14
:  3

S6 : 12

:  10
:  1
:  15
:  10
:  4
:  15
:  2
:  9
:  7
:  2
:  12
:  6
:  9
:  8
:  5
:  0
:  6
:  13
:  1
:  3
:  13
:  4
:  14
:  14
:  0
:  7
:  11
:  5
:  3
:  11
:  8
:  9
:  4
:  14
:  3
:  15
:  2
:  5
:  12
:  2
:  9
:  8
:  5
:  12
:  15
:  3
:  10
:  7
:  11
:  0
:  14
:  4
:  1
:  10
:  7
:  1
:  6
:  13
:  0
:  11
:  8
:  6
:  13

S7 : 4

:  13
:  11
:  0
:  2
:  11
:  14
:  7
:  15
:  4
:  0
:  9
:  8
:  1
:  13
:  10
:  3
:  14
:  12
:  3
:  9
:  5
:  7
:  12
:  5
:  2
:  10
:  15
:  6
:  8
:  1
:  6
:  1
:  6
:  4
:  11
:  11
:  13
:  13
:  8
:  12
:  1
:  3
:  4
:  7
:  10
:  14
:  7
:  10
:  9
:  15
:  5
:  6
:  0
:  8
:  15
:  0
:  14
:  5
:  2
:  9
:  3
:  2
:  12

S8 : 13

:  1
:  2
:  15
:  8
:  13
:  4
:  8
:  6
:  10
:  15
:  3
:  11
:  7
:  1
:  4
:  10
:  12
:  9
:  5
:  3
:  6
:  14
:  11
:  5
:  0
:  0
:  14
:  12
:  9
:  7
:  2
:  7
:  2
:  11
:  1
:  4
:  14
:  1
:  7
:  9
:  4
:  12
:  10
:  14
:  8
:  2
:  13
:  0
:  15
:  6
:  12
:  10
:  9
:  13
:  0
:  15
:  3
:  3
:  5
:  5
:  6
:  8
:  11

DesShifts : 1

:  1
:  2
:  2
:  2
:  2
:  2
:  2
:  1
:  2
:  2
:  2
:  2
:  2
:  2
:  1

DesHex : 0

:   0
:   0
:   0
:   0
:   0
:   0
:   1
:   0
:   0
:   1
:   0
:   0
:   0
:   1
:   1
:   0
:   1
:   0
:   0
:   0
:   1
:   0
:   1
:   0
:   1
:   1
:   0
:   0
:   1
:   1
:   1
:   1
:   0
:   0
:   0
:   1
:   0
:   0
:   1
:   1
:   0
:   1
:   0
:   1
:   0
:   1
:   1
:   1
:   1
:   0
:   0
:   1
:   1
:   0
:   1
:   1
:   1
:   1
:   0
:   1
:   1
:   1
:   1

DesC  : 28 0 DesD  : 28 0 DesL  : 32 0 DesR  : 32 0 DesL1  : 32 0 DesR1  : 32 0 DesEK  : 48 0 DesK  : 768 0 DesWds  : 64 0

DesI  : 0 DesJ  : 0 DesJJ  : 0xf000 DesIter  : 0 DesSNum  : 0 OldDesKeyW : -1 DesKeyW  : 0 DesDataW : 0 DesKey = DesKeyW DesData = DesDataW K : 0 Kc = K

kprime : x'0e329232ea6d0d73'

dprime : x'8787878787878787'


| Program Starts Here


kprime deskey         | Load encryption key 
dprime desdata        | Load data to be encrypted 
call dodeskey         | Perform key setup
call encryptdes       | Encrypt data
desdata $s            | Move encrypted data to string
unpackhex $s          | Unpack to display
$s []                 | Display
stop


| End of Program


Data2Wds

       63 DesJJ
       7 DesI
       if DesI GE 0
          DesData.DesI D
          DesJ
          if DesJ LE 7
             and 1 D D1
             D1 DesWds.DesJJ
             shr D 1
             - DesJJ
             + DesJ
             goif
          endif
          - DesI
          goif
       endif
       return

Wds2Data

       DesJJ              
       DesI               
       if DesI LE 7       
           DesJ           
           if DesJ LE 7               
              shl D 1        
              if DesWds.DesJJ NE 0           
                  + D        
              endif
              + DesJJ
              + DesJ
              goif
           endif              
           D DesData.DesI       
           + DesI
           goif
       endif
       return

Key2Wds

  63 DesJJ                     
  7 DesI                       
  if DesI GE 0                 
     DesKey.DesI K             
     DesJ                      
     if DesJ LE 7              
        and K 1 K1
        K1 DesWds.DesJJ        

shr K 1

        - DesJJ                
        + DesJ                 
        goif                   
     endif                     
     - DesI                    
     goif                      
  endif                        
  return                       

func

   DesI
   if DesI LE 47
      Ebit.DesI rx
      DesR.rx DesEK.DesI
      + DesI
      goif
   endif
   * 48 DesIter DesJ
   DesI
   if DesI LE 47
      + DesI DesJ IJ
      xor DesEK.DesI DesK.IJ DesEK.DesI
      + DesI
      goif
   endif
   DesI
   DesSNum
   if DesSNum LE 7
      DesEK.DesI ss
      shl ss 1
      + DesI
      + DesEK.DesI ss
      shl ss 1
      + DesI
      + DesEK.DesI ss
      shl ss 1
      + DesI
      + DesEK.DesI ss
      shl ss 1
      + DesI
      + DesEK.DesI ss
      shl ss 1
      + DesI
      + DesEK.DesI ss
      + DesI
      DesSNum DesS1x
      Shl DesS1x 6
      + ss DesS1x
      DesS1.DesS1x DesHexx
      shl DesHexx 2
      DesSNum DesWdsx
      shl DesWdsx 2
      DesHex.DesHexx DesWds.DesWdsx 4
      + DesSNum
      goif
   endif
   DesI
   if DesI LE 31
      P.DesI DesJ
      DesWds.DesJ DesR.DesI
      + DesI
      goif
   endif
   return

DoDesKey

   if DesKeyW EQ OldDesKeyW
      if DesJJ NE 0xf000
         return
      endif
   endif
   DesKeyW OldDesKeyW
   call Key2Wds
   DesI
   if DesI LE 55
      Pc1.DesI Pcx
      DesWds.Pcx DesC.DesI
      + DesI
      goif
   endif
   DesJJ
   DesI
   if DesI LE 15
      DesC.0 DesWd
      DesC.1 DesC 27
      DesWd DesC.27
      DesD.0 DesWd
      DesD.1 DesD 27
      DesWd DesD.27
      if DesShifts.DesI EQ 2
          DesC.0 DesWd
          DesC.1 DesC 27
          DesWd DesC.27
          DesD.0 DesWd
          DesD.1 DesD 27
          DesWd DesD.27
      endif
      DesJ
      if DesJ LE 47
         Pc2.DesJ DesCx
         DesC.DesCx DesK.DesJJ
         + DesJJ
         + DesJ
         goif
      endif
      + DesI
      goif
   endif
   return

EncryptDes

    Call Data2Wds
    DesI
    if DesI LE 63
       DesIP.DesI DesWdsx
       DesWds.DesWdsx DesL.DesI
       + DesI
       goif
    endif
    DesIter
    if DesIter LE 15
       DesR DesL1 32
       call func
       DesJ
       if DesJ LE 31
          xor DesL.DesJ DesR.DesJ
          + DesJ
          goif
       endif
       DesL1 DesL 32
       + DesIter
       goif
    endif
    DesL DesR1 32
    DesR DesL1 32
    DesI
    if DesI LE 63
       DesIPIV.DesI DesL1x
       DesL1.DesL1x DesWds.DesI
       + DesI
       goif
    endif
    call Wds2Data
    return

DecryptDes

    Call Data2Wds
    DesI
    if DesI LE 63
       DesIP.DesI DesWdsx
       DesWds.DesWdsx DesL.DesI
       + DesI
       goif
    endif
    15 DesIter
    if DesIter GE 0
       DesR DesL1 32
       call func
       DesJ
       if DesJ LE 31
          xor DesL.DesJ DesR.DesJ
          + DesJ
          goif
       endif
       DesL1 DesL 32
       - DesIter
       goif
    endif
    DesL DesR1 32
    DesR DesL1 32
    DesI
    if DesI LE 63
       DesIPIV.DesI DesL1x
       DesL1.DesL1x DesWds.DesI
       + DesI
       goif
    endif
    call Wds2Data
    return</lang>

A trivial solution using the des encryption instruction: <lang>key : x'0e329232ea6d0d73' data : x'8787878787878787'

edes key data            | encrypt data with key 
data $s                  | move data to string
unpackhex $s $s          | unpack
$s []                    | output result - 0000000000000000

</lang>

Output:
0000000000000000