Data Encryption Standard
Demonstrate the Data Encryption Standard. For a complete description of the algorithm see: The DES Algorithm Illustrated
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
<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
F#
<lang fsharp>open System open System.Security.Cryptography open System.IO
let ByteArrayToString ba =
ba |> Array.map (fun (b : byte) -> b.ToString("X2")) |> String.Concat
let Encrypt passwordBytes messageBytes =
// Configure encryption settings let iv = Array.zeroCreate 8 let provider = new DESCryptoServiceProvider() let transform = provider.CreateEncryptor(passwordBytes, iv)
// Setup streams and encrypt let memStream = new MemoryStream() let cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write) cryptoStream.Write(messageBytes, 0, messageBytes.Length) cryptoStream.FlushFinalBlock()
// Read the encrypted message from the stream let encryptedMessageBytes = Array.zeroCreate ((int) memStream.Length) memStream.Position <- 0L memStream.Read(encryptedMessageBytes, 0, encryptedMessageBytes.Length) |> ignore
// Return the encrypted bytes encryptedMessageBytes
let Decrypt passwordBytes encryptedBytes =
// Configure encryption settings let iv = Array.zeroCreate 8 let provider = new DESCryptoServiceProvider() let transform = provider.CreateDecryptor(passwordBytes, iv)
// Setup streams and decrypt let memStream = new MemoryStream() let cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write) cryptoStream.Write(encryptedBytes, 0, encryptedBytes.Length) cryptoStream.FlushFinalBlock()
// Read the message from the stream let messageBytes = Array.zeroCreate ((int) memStream.Length) memStream.Position <- 0L memStream.Read(messageBytes, 0, messageBytes.Length) |> ignore
// Return the encrypted bytes messageBytes
[<EntryPoint>] let main _ =
let keyBytes = [|0x0euy; 0x32uy; 0x92uy; 0x32uy; 0xeauy; 0x6duy; 0x0duy; 0x73uy|] let plainbytes = [|0x87uy; 0x87uy; 0x87uy; 0x87uy; 0x87uy; 0x87uy; 0x87uy; 0x87uy|]
let encStr = Encrypt keyBytes plainbytes printfn "Encoded: %s" (ByteArrayToString encStr)
let decBytes = Decrypt keyBytes encStr printfn "Decoded: %s" (ByteArrayToString decBytes)
0 // return an integer exit code</lang>
- Output:
Encoded: 0000000000000000A913F4CB0BD30F97 Decoded: 8787878787878787
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
<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
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
implemented like in the article linked in description.
really good article btw
<lang Python>#!/usr/bin/python
- 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