Data Encryption Standard: Difference between revisions
Line 632: | Line 632: | ||
function get_subkeys(string key) |
function get_subkeys(string key) |
||
if length(key)!=8 then ?9/0 end if -- 64 bits |
|||
⚫ | |||
if length(key)!=8 then ?9/0 end if |
|||
kp = repeat(0,56) |
|||
-- permute 'key' using table PC1 |
|||
⚫ | |||
for i=1 to 56 do kp[i] = k[PC1[i]] end for |
for i=1 to 56 do kp[i] = k[PC1[i]] end for |
||
⚫ | |||
-- split 'kp' in half and process the resulting series of 'c' and 'd' |
|||
⚫ | |||
⚫ | |||
⚫ | |||
for i=1 to 16 do |
for i=1 to 16 do |
||
integer shift = SHIFTS[i] |
integer shift = SHIFTS[i] |
||
Line 647: | Line 644: | ||
cn[i] = c&d |
cn[i] = c&d |
||
end for |
end for |
||
-- form the sub-keys and store them in 'ks' |
|||
sequence ks = repeat(repeat('\0',48),16) |
sequence ks = repeat(repeat('\0',48),16) |
||
-- permute 'c' using table PC2 |
|||
for i=1 to 16 do |
for i=1 to 16 do |
||
for j=1 to 48 do ks[i][j] = cn[i][PC2[j]] end for |
for j=1 to 48 do ks[i][j] = cn[i][PC2[j]] end for |
||
Line 657: | Line 652: | ||
function f(sequence r, kn) |
function f(sequence r, kn) |
||
-- permute 'r' using table E and xor with k[n] |
|||
sequence er = repeat('\0',48) |
sequence er = repeat('\0',48) |
||
for i=1 to 48 do er[i] = r[E[i]] xor kn[i] end for |
for i=1 to 48 do er[i] = r[E[i]] xor kn[i] end for |
||
Line 668: | Line 662: | ||
sr[n..n+3] = sprintf("%04b",S[i][k]) |
sr[n..n+3] = sprintf("%04b",S[i][k]) |
||
end for |
end for |
||
-- lastly permute sr using table P |
|||
sequence sp = repeat('\0',32) |
sequence sp = repeat('\0',32) |
||
for i=1 to 32 do sp[i] = sr[P[i]]-'0' end for |
for i=1 to 32 do sp[i] = sr[P[i]]-'0' end for |
||
Line 676: | Line 669: | ||
function process_block(string message, sequence k) |
function process_block(string message, sequence k) |
||
if length(message)!=8 then ?9/0 end if -- 64 bit blocks |
if length(message)!=8 then ?9/0 end if -- 64 bit blocks |
||
sequence m = to_64bits(message) |
sequence m = to_64bits(message), |
||
⚫ | |||
-- permute 'message' using table IP |
|||
⚫ | |||
for i=1 to 64 do mp[i] = m[IP[i]] end for |
for i=1 to 64 do mp[i] = m[IP[i]] end for |
||
sequence {l,r} = {mp[1..32],mp[33..64]} |
sequence {l,r} = {mp[1..32],mp[33..64]} |
||
Line 685: | Line 677: | ||
end for |
end for |
||
sequence e = r&l |
sequence e = r&l |
||
-- permute 'e' using table IP_1 and return result as a hex string |
|||
string res = "" |
string res = "" |
||
integer byte = 0, bit = 0 |
integer byte = 0, bit = 0 |
||
Line 728: | Line 719: | ||
for i=1 to length(TESTS) do |
for i=1 to length(TESTS) do |
||
string { |
string {key,msg,expect} = TESTS[i], |
||
keytxt = as_hex(key), |
|||
msgtxt = iff(i<=2?as_hex(msg):sprint(msg)), |
|||
⚫ | |||
⚫ | |||
⚫ | |||
enctxt = as_hex(encoded), |
enctxt = as_hex(encoded), |
||
error = iff(enctxt= |
error = iff(enctxt=expect?"":"\n********* "&expect&" expected"), |
||
⚫ | |||
⚫ | |||
⚫ | |||
printf(1,"Key : %s\n",{keytxt}) |
|||
⚫ | |||
printf(1,"Encoded : %s%s\n",{enctxt,error}) |
printf(1,"Encoded : %s%s\n",{enctxt,error}) |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end for</lang> |
end for</lang> |
||
{{out}} |
{{out}} |
Revision as of 12:08, 11 September 2018
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.
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 if (r != 0) { val len = (1 + m.length / 16) * 16 m = m.padEnd(len, '0') // pad with zeros for simplicity } 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() }
/* any padding is assumed to be in the form of trailing zeros following 0DOA; only the zeros will be removed */ fun decrypt(key: String, encoded: String, removePadding: Boolean = false): 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) } var decoded = sb.toString() if (removePadding && decoded.indexOf("0D0A") > -1) decoded = decoded.trimEnd('0') return decoded }
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] f(r[0], ks[1]) 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" ) val padding = booleanArrayOf(false, false, true) 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, padding[i]) println("Decoded : $decoded") println() }
}</lang>
- Output:
Key : 133457799BBCDFF1 Message : 0123456789ABCDEF Encoded : 85E813540F0AB405 Decoded : 0123456789ABCDEF Key : 0E329232EA6D0D73 Message : 8787878787878787 Encoded : 0000000000000000 Decoded : 8787878787878787 Key : 0E329232EA6D0D73 Message : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F5358499828AC9B453E0E653 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]); 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
plain := BA{38H, 37H, 38H, 37H, 38H, 37H, 38H, 37H, 38H, 37H, 38H, 37H, 38H, 37H, 38H, 37H};
key[0] := Key1{0EH, 32H, 92H, 32H, 0EAH, 6DH, 0DH, 73H}; cipher := Create(key);
WriteString("plain: "); WriteString(plain); WriteLn;
EncryptECB(cipher,ADR(plain),ADR(encrypt),16);
WriteString("encrypt: "); PrintHexBytes(encrypt, 16); WriteLn;
DecryptECB(cipher,ADR(encrypt),ADR(plain),16);
WriteString("plain: "); WriteString(plain); WriteLn;
Destroy(cipher); ReadChar
END DataEncryptionStandard.</lang>
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.
Note: padding/trimming is the responsibility of the caller. (0D0A terminator/null padding may be wholly inappropriate in some cases.) <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 to_64bits(string s)
sequence res = "" for i=1 to length(s) do res &= sprintf("%08b",s[i]) end for res = sq_sub(res,'0') return res
end function
function get_subkeys(string key)
if length(key)!=8 then ?9/0 end if -- 64 bits sequence k = to_64bits(key), kp = repeat(0,56) for i=1 to 56 do kp[i] = k[PC1[i]] end for sequence {c,d} = {kp[1..28],kp[29..56]}, cn = repeat(0,16) for i=1 to 16 do integer shift = SHIFTS[i] c = c[shift+1..$]&c[1..shift] d = d[shift+1..$]&d[1..shift] cn[i] = c&d end for sequence ks = repeat(repeat('\0',48),16) for i=1 to 16 do for j=1 to 48 do ks[i][j] = cn[i][PC2[j]] end for end for return ks
end function
function f(sequence r, kn)
sequence er = repeat('\0',48) for i=1 to 48 do er[i] = r[E[i]] xor kn[i] end for -- process 'er' six bits at a time and store resulting four bits in 'sr' sequence sr = repeat('\0',32) 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, n = (i-1)*4+1 sr[n..n+3] = sprintf("%04b",S[i][k]) end for sequence sp = repeat('\0',32) for i=1 to 32 do sp[i] = sr[P[i]]-'0' end for return sp
end function
function process_block(string message, sequence k)
if length(message)!=8 then ?9/0 end if -- 64 bit blocks sequence m = to_64bits(message), mp = repeat('\0',64) for i=1 to 64 do mp[i] = m[IP[i]] end for sequence {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 sequence e = r&l string res = "" integer byte = 0, bit = 0 for i=1 to 64 do byte = byte*2+e[IP_1[i]] bit += 1 if bit=8 then res &= byte byte = 0 bit = 0 end if 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) 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 return res
end function
constant TESTS = {{x"133457799BBCDFF1", x"0123456789ABCDEF", "85E813540F0AB405"},
{x"0E329232EA6D0D73", x"8787878787878787", "0000000000000000"}, {x"0E329232EA6D0D73",
-- x"596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A0000",
"Your lips are smoother than vaseline\r\n\0\0", -- (pre-padded, see note) "C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F5358499828AC9B453E0E653"}}
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<=2?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<=2?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 : 85E813540F0AB405 Decoded : 0123456789ABCDEF Key : 0E329232EA6D0D73 Message : 8787878787878787 Encoded : 0000000000000000 Decoded : 8787878787878787 Key : 0E329232EA6D0D73 Message : "Your lips are smoother than vaseline\r\n\0\0" Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F5358499828AC9B453E0E653 Decoded : "Your lips are smoother than vaseline\r\n\0\0"
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