Data Encryption Standard: Difference between revisions

Rename Perl 6 -> Raku, alphabetize, minor clean-up
m (→‎{{header|Perl 6}}: try replacing pack/unpack)
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 11:
 
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.
 
 
=={{header|C}}==
Line 531 ⟶ 530:
Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
Decoded : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A</pre>
 
=={{header|C sharp|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>
{{out}}
<pre>Encoded: 0000000000000000A913F4CB0BD30F97
Decoded: 8787878787878787</pre>
 
=={{header|C++}}==
Line 971 ⟶ 1,046:
Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
Decoded : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A</pre>
 
=={{header|C#|C sharp}}==
<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>
{{out}}
<pre>Encoded: 0000000000000000A913F4CB0BD30F97
Decoded: 8787878787878787</pre>
 
=={{header|D}}==
Line 1,506 ⟶ 1,505:
<pre>Encoded: 0000000000000000A913F4CB0BD30F97
Decoded: 8787878787878787</pre>
 
=={{header|FreeBASIC}}==
<lang freebasic>' version 20-01-2019
Line 1,881:
<pre>Encoded: 0000000000000000a913f4cb0bd30f97
Decoded: 8787878787878787</pre>
 
=={{header|Julia}}==
===Using the MbedTLS library===
<lang julia>using MbedTLS
 
const testdata = [
[[0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1],
[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[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]]
]
 
for (key, message) in testdata
println("Key : $(bytes2hex(key))")
println("Message : $(bytes2hex(message))")
encoded = encrypt(CIPHER_DES, key, message)
println("Encoded : $(bytes2hex(encoded))")
decoded = decrypt(CIPHER_DES, key, encoded)
println("Decoded : $(bytes2hex(decoded))\n")
end
</lang>{{out}}
<pre>
Key : 133457799bbcdff1
Message : 0123456789abcdef
Encoded : 85e813540f0ab40577a2a9308f18d27b
Decoded : 0123456789abcdef
 
Key : 0e329232ea6d0d73
Message : 8787878787878787
Encoded : 0000000000000000a913f4cb0bd30f97
Decoded : 8787878787878787
 
Key : 0e329232ea6d0d73
Message : 596f7572206c6970732061726520736d6f6f74686572207468616e20766173656c696e650d0a
Encoded : c0999fdde378d7edcf813f0a8d57a539f61a9b5422a7265495b67b084b57a30700e799f58325c7b6
Decoded : 596f7572206c6970732061726520736d6f6f74686572207468616e20766173656c696e650d0a
</pre>
===Base Julia only===
{{trans|Phix}}
<lang julia>const 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]
const SHIFTS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
const 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]
const 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]
const 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]
const 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]]
const 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]
const 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 getsubkeys(key::Vector{UInt8})
b = mapreduce(x -> reverse(digits(x, base=2, pad=8)), vcat, key)
kp = [UInt8(b[PC1[i]]) for i in 1:length(PC1)]
ks = [zeros(UInt8, 48) for _ in 1:16]
for i in 1:16
shift = SHIFTS[i]
kp = vcat(kp[shift+1:28], kp[1:shift], kp[shift+29:end], kp[29:shift+28])
for j in 1:48
ks[i][j] = kp[PC2[j]]
end
end
return ks
end
function f(r::Vector{UInt8}, kn::Vector{UInt8})
er, sr = [r[E[i]] ⊻ kn[i] for i in 1:48], UInt8[]
# process er six bits at a time, a total of 8 times for 48 values
for i in 1:8
j = (i - 1) * 6 + 1
k = sum(er[j:j+5] .* [32, 8, 4, 2, 1, 16]) + 1
sr = vcat(sr, UInt8.(reverse(digits(S[i][k], base=2, pad=4))))
end
return [sr[P[i]] for i in 1:32]
end
function processblock(messageblock::Vector{UInt8}, subkeys)
b = mapreduce(x -> reverse(digits(x, base=2, pad=8)), vcat, messageblock)
mp = [UInt8(b[IP[i]]) for i in 1:length(IP)]
left, right = mp[1:32], mp[33:end]
for n in 1:16
left, right = right, left .⊻ f(right, subkeys[n])
end
e, result = vcat(right, left), UInt8[]
for i in 0:8:63
byte = 0
for bit in 1:8
byte = byte * 2 + e[IP_1[i + bit]]
end
push!(result, byte)
end
return result
end
 
function des(key, message, isdecode)
k = getsubkeys(key)
if isdecode
k = reverse(k)
if length(message) % 8 != 0
throw(InexactError("Message to decode must have length a multiple of 8"))
end
else
# pad message to have a length of a multiple of the 8 byte block size
p = UInt8(8 - length(message) % 8)
message = vcat(message, fill(p, p))
end
result = zeros(UInt8, length(message))
@Threads.threads for i in 1:8:length(message)-1
result[i:i+7] .= processblock(message[i:i+7], k)
end
if isdecode
# truncate based on last byte
result = result[1:end-result[end]]
end
return result
end
 
const testdata = [
[[0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1],
[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[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]]
]
 
for (key, message) in testdata
println("Key : $(bytes2hex(key))")
println("Message : $(bytes2hex(message))")
encoded = des(key, message, false)
println("Encoded : $(bytes2hex(encoded))")
decoded = des(key, encoded, true)
println("Decoded : $(bytes2hex(decoded))\n")
end
</lang>
Output: same as MbedTLS library version above.
 
=={{header|Kotlin}}==
Line 2,265 ⟶ 2,475:
Encoded : C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
Decoded : 596F7572206C6970732061726520736D6F6F74686572207468616E20766173656C696E650D0A</pre>
 
 
=={{header|Julia}}==
===Using the MbedTLS library===
<lang julia>using MbedTLS
 
const testdata = [
[[0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1],
[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[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]]
]
 
for (key, message) in testdata
println("Key : $(bytes2hex(key))")
println("Message : $(bytes2hex(message))")
encoded = encrypt(CIPHER_DES, key, message)
println("Encoded : $(bytes2hex(encoded))")
decoded = decrypt(CIPHER_DES, key, encoded)
println("Decoded : $(bytes2hex(decoded))\n")
end
</lang>{{out}}
<pre>
Key : 133457799bbcdff1
Message : 0123456789abcdef
Encoded : 85e813540f0ab40577a2a9308f18d27b
Decoded : 0123456789abcdef
 
Key : 0e329232ea6d0d73
Message : 8787878787878787
Encoded : 0000000000000000a913f4cb0bd30f97
Decoded : 8787878787878787
 
Key : 0e329232ea6d0d73
Message : 596f7572206c6970732061726520736d6f6f74686572207468616e20766173656c696e650d0a
Encoded : c0999fdde378d7edcf813f0a8d57a539f61a9b5422a7265495b67b084b57a30700e799f58325c7b6
Decoded : 596f7572206c6970732061726520736d6f6f74686572207468616e20766173656c696e650d0a
</pre>
===Base Julia only===
{{trans|Phix}}
<lang julia>const 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]
const SHIFTS = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
const 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]
const 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]
const 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]
const 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]]
const 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]
const 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 getsubkeys(key::Vector{UInt8})
b = mapreduce(x -> reverse(digits(x, base=2, pad=8)), vcat, key)
kp = [UInt8(b[PC1[i]]) for i in 1:length(PC1)]
ks = [zeros(UInt8, 48) for _ in 1:16]
for i in 1:16
shift = SHIFTS[i]
kp = vcat(kp[shift+1:28], kp[1:shift], kp[shift+29:end], kp[29:shift+28])
for j in 1:48
ks[i][j] = kp[PC2[j]]
end
end
return ks
end
function f(r::Vector{UInt8}, kn::Vector{UInt8})
er, sr = [r[E[i]] ⊻ kn[i] for i in 1:48], UInt8[]
# process er six bits at a time, a total of 8 times for 48 values
for i in 1:8
j = (i - 1) * 6 + 1
k = sum(er[j:j+5] .* [32, 8, 4, 2, 1, 16]) + 1
sr = vcat(sr, UInt8.(reverse(digits(S[i][k], base=2, pad=4))))
end
return [sr[P[i]] for i in 1:32]
end
function processblock(messageblock::Vector{UInt8}, subkeys)
b = mapreduce(x -> reverse(digits(x, base=2, pad=8)), vcat, messageblock)
mp = [UInt8(b[IP[i]]) for i in 1:length(IP)]
left, right = mp[1:32], mp[33:end]
for n in 1:16
left, right = right, left .⊻ f(right, subkeys[n])
end
e, result = vcat(right, left), UInt8[]
for i in 0:8:63
byte = 0
for bit in 1:8
byte = byte * 2 + e[IP_1[i + bit]]
end
push!(result, byte)
end
return result
end
 
function des(key, message, isdecode)
k = getsubkeys(key)
if isdecode
k = reverse(k)
if length(message) % 8 != 0
throw(InexactError("Message to decode must have length a multiple of 8"))
end
else
# pad message to have a length of a multiple of the 8 byte block size
p = UInt8(8 - length(message) % 8)
message = vcat(message, fill(p, p))
end
result = zeros(UInt8, length(message))
@Threads.threads for i in 1:8:length(message)-1
result[i:i+7] .= processblock(message[i:i+7], k)
end
if isdecode
# truncate based on last byte
result = result[1:end-result[end]]
end
return result
end
 
const testdata = [
[[0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1],
[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87]],
[[0x0E, 0x32, 0x92, 0x32, 0xEA, 0x6D, 0x0D, 0x73],
[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]]
]
 
for (key, message) in testdata
println("Key : $(bytes2hex(key))")
println("Message : $(bytes2hex(message))")
encoded = des(key, message, false)
println("Encoded : $(bytes2hex(encoded))")
decoded = des(key, encoded, true)
println("Decoded : $(bytes2hex(decoded))\n")
end
</lang>
Output: same as MbedTLS library version above.
 
=={{header|Modula-2}}==
Line 2,536 ⟶ 2,535:
encrypt: 0000000000000000A913F4CB0BD30F97
plain: 8787878787878787</pre>
 
=={{header|Perl 6}}==
This is mainly a translation from the Phix entry, with an additional example on UTF-8. Regarding the many conversions among different number/string formats, small (and hopefully reusable ) helper routines are created to serve the purpose.
Update 20190323: After a bug fixed an example does behave correctly and is now in line with the results from the C, D, Kotlin and Phix entries. By the way it seems ''.comb'' handle "\r\n" inconsistently, why? [https://pastebin.com/d7dBpYkL]
Update 20190325: Thanks to SqrtNegInf for pointing out that the answer is already in the documentation.[https://docs.perl6.org/type/Str#routine_chomp], [https://docs.perl6.org/language/newline]
{{trans|Phix}}
<lang perl6>#!/usr/bin/env perl6
use v6.d;
#use experimental :pack;
my \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
>; # Permuted choice 1 (PC-1) - Parity Drop Table
my \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
>; # Permuted choice 2 (PC-2) - Key Compression Table
my \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
>; # Initial permutation (IP)
my \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
>; # Final permutation (IP⁻¹)
my \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
> ); # 8 Substitution boxes, each replaces a 6-bit input with a 4-bit output
my \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
>; # Permutation (P), shuffles the bits of a 32-bit half-block
# Expansion function (E), expand 32-bit half-block to 48 bits
my \E = flat 32,1..5,4..9,8..13,12..17,16..21,20..25,24..29,28..32,1;
my \SHIFTS = < 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 >; # schedule of left shifts
## Helper subs
# convert iso-8859-1 to hexadecimals
#sub b2h (\b) { [~] map { .encode('iso-8859-1').unpack('H*') }, b.comb };
sub b2h (\b) { b.ords.fmt('%02X', '') };
 
# convert UTF8s to bytes
sub u2b (\u) { [~] map { .chr }, @( [~] map { .encode('utf8') }, u.comb) };
# convert hexadecimals to UTF-8
#sub h2u (\h) { pack("H" x h.chars/2, h ~~ m:g/../).decode('utf8') };
sub h2u (\h) { Blob.new( h.comb(2).map: { :16( $_ ) } ).decode('utf8') };
 
# convert quadbits to hex
sub q2h (\q) { [~] map { :2($_.Str).fmt('%X') }, q ~~ m:g/..../ };
# convert every two quadbits to bytes
sub q2b (\q) { map { :2($_.Str) }, q ~~ m:g/. ** 8/ };
# trun a 16 digit hexadecimal str to a 64 bits list
sub h2bits (\h) { ([~] map { :16($_).base(2).fmt('%04s') }, h.comb).split("")[1..64] };
sub infix:<⥀>(\a is copy, \b) { a.append: a.shift for ^b ; a } # XOR addition
# convert hexadecimals to bytes
sub h2bytes (\h) { [~] map { :16($_.Str).chr }, h ~~ m:g/../ };
# s is 16 digit hexadecimal str, M is a permuation matrix/vector
sub map64(\s, \M) { my \b = h2bits s; map { b[$_-1] }, M; }
## Core subs
sub get_subkeys(Str \key --> Seq) { # return a Seq with 16 bit vectors
my \Kₚ = map64 key, PC1; # drop parity bits
my @C = Kₚ[0..27] ; my @D = Kₚ[28..55]; # perform bits rotation next
my \CD = map { [ flat @C ⥀= SHIFTS[$_], @D ⥀= SHIFTS[$_] ]}, ^16;
return map { map { CD[$_][PC2[$^a]-1] }, ^48 }, ^16; # key compression rounds
}
sub ƒ (List \R is copy, Seq \Kₙ is copy --> Seq) {
my @er = map { Kₙ[$_] +^ R[E[$_]-1] }, ^48;
my @sr = flat map { # Sₙ(Bₙ) loop, process @er six bits at a time
((S.[$_][([~] @er[$_*6,$_*6+5]).parse-base(2)*16+([~]
@er[$_*6+1 .. $_*6+4]).parse-base(2)]).fmt('%04b').split(""))[1..4]
}, ^8;
return map { @sr[$_-1] }, P;
}
sub process_block(Str \message, \K is copy --> Str) { # return 8 quadbits
my \mp = map64 (b2h message) , IP; # turn message to hex then map to bits
my @L = mp[0..31]; my @R = mp[32..63];
my (@Lₙ , @Rₙ); # then apply 16 iterations with function ƒ
{ @Lₙ = @R; @Rₙ = @L Z+^ ƒ @R, K[$_]; @L = @Lₙ; @R = @Rₙ } for ^16;
my \res = flat @R, @L; # reverse and join the final L₁₆ and R₁₆
return [~] map { res[$_-1] }, IP2 ; # inverse of the initial permutation
}
sub des(Str \key, Str $msg is copy, Bool \DECODE --> Str) { # return hexdecimal
my @K; my \length = $msg.encode('iso-8859-1').bytes;
if ( DECODE and length % 8 ) { # early exit, avoid the subkeys computation
die "Message must be in multiples of 8 bytes"
} else {
@K = DECODE ?? reverse get_subkeys key !! get_subkeys key
}
{ my \P = 8 - length % 8; # number of pad bytes
$msg ~= P.chr x P ; # CMS style padding as per RFC 1423 & RFC 5652
} unless DECODE;
 
my $quad ~= process_block substr($msg,$_,8), @K for
0, 8 … $msg.encode('iso-8859-1').bytes-8;
 
{ my @decrypt = q2b $quad; # quadbits to a byte code point list
@decrypt.pop xx @decrypt.tail; # remove padding
return b2h ( [~] map { .chr } , @decrypt )
} if DECODE ;
return q2h $quad
}
say "Encryption examples: ";
say des "133457799BBCDFF1", h2bytes("0123456789ABCDEF"), False;
say des "0E329232EA6D0D73", h2bytes("8787878787878787"), False;
say des "0E329232EA6D0D73", "Your lips are smoother than vaseline", False;
say des "0E329232EA6D0D73", "Your lips are smoother than vaseline\r\n", False;
say des "0E329232EA6D0D73", u2b("BMP: こんにちは ; Astral plane: 𝒳𝒴𝒵"), False;
say "Decryption examples: ";
say des "133457799BBCDFF1", h2bytes("85E813540F0AB405FDF2E174492922F8"), True;
say des "0E329232EA6D0D73", h2bytes("0000000000000000A913F4CB0BD30F97"), True;
say h2bytes des "0E329232EA6D0D73", h2bytes("C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F535849980A2E7453703513E"), True;
say h2bytes des "0E329232EA6D0D73", h2bytes("C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99"), True;
say h2u des "0E329232EA6D0D73", h2bytes("C040FB6A6E72D7C36D60CA9B9A35EB38D3194468AD808103C28E33AEF0B268D0E0366C160B028DDACF340003DCA8969343EBBD289DB94774"), True;</lang>
{{out}}
<pre>Encryption examples:
85E813540F0AB405FDF2E174492922F8
0000000000000000A913F4CB0BD30F97
C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F535849980A2E7453703513E
C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
C040FB6A6E72D7C36D60CA9B9A35EB38D3194468AD808103C28E33AEF0B268D0E0366C160B028DDACF340003DCA8969343EBBD289DB94774
Decryption examples:
0123456789abcdef
8787878787878787
Your lips are smoother than vaseline
Your lips are smoother than vaseline
 
BMP: こんにちは ; Astral plane: 𝒳𝒴𝒵</pre>
 
=={{header|Phix}}==
Line 3,193 ⟶ 3,012:
encrypted: 85e813540f0ab405
decrypted: 123456789abcdef</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
This is mainly a translation from the Phix entry, with an additional example on UTF-8. Regarding the many conversions among different number/string formats, small (and hopefully reusable ) helper routines are created to serve the purpose.
Update 20190323: After a bug fixed an example does behave correctly and is now in line with the results from the C, D, Kotlin and Phix entries. By the way it seems ''.comb'' handle "\r\n" inconsistently, why? [https://pastebin.com/d7dBpYkL]
Update 20190325: Thanks to SqrtNegInf for pointing out that the answer is already in the documentation.[https://docs.perl6.org/type/Str#routine_chomp], [https://docs.perl6.org/language/newline]
{{trans|Phix}}
<lang perl6>#!/usr/bin/env perl6
use v6.d;
#use experimental :pack;
my \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
>; # Permuted choice 1 (PC-1) - Parity Drop Table
my \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
>; # Permuted choice 2 (PC-2) - Key Compression Table
my \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
>; # Initial permutation (IP)
my \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
>; # Final permutation (IP⁻¹)
my \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
> ); # 8 Substitution boxes, each replaces a 6-bit input with a 4-bit output
my \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
>; # Permutation (P), shuffles the bits of a 32-bit half-block
# Expansion function (E), expand 32-bit half-block to 48 bits
my \E = flat 32,1..5,4..9,8..13,12..17,16..21,20..25,24..29,28..32,1;
my \SHIFTS = < 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 >; # schedule of left shifts
## Helper subs
# convert iso-8859-1 to hexadecimals
#sub b2h (\b) { [~] map { .encode('iso-8859-1').unpack('H*') }, b.comb };
sub b2h (\b) { b.ords.fmt('%02X', '') };
 
# convert UTF8s to bytes
sub u2b (\u) { [~] map { .chr }, @( [~] map { .encode('utf8') }, u.comb) };
# convert hexadecimals to UTF-8
#sub h2u (\h) { pack("H" x h.chars/2, h ~~ m:g/../).decode('utf8') };
sub h2u (\h) { Blob.new( h.comb(2).map: { :16( $_ ) } ).decode('utf8') };
 
# convert quadbits to hex
sub q2h (\q) { [~] map { :2($_.Str).fmt('%X') }, q ~~ m:g/..../ };
# convert every two quadbits to bytes
sub q2b (\q) { map { :2($_.Str) }, q ~~ m:g/. ** 8/ };
# trun a 16 digit hexadecimal str to a 64 bits list
sub h2bits (\h) { ([~] map { :16($_).base(2).fmt('%04s') }, h.comb).split("")[1..64] };
sub infix:<⥀>(\a is copy, \b) { a.append: a.shift for ^b ; a } # XOR addition
# convert hexadecimals to bytes
sub h2bytes (\h) { [~] map { :16($_.Str).chr }, h ~~ m:g/../ };
# s is 16 digit hexadecimal str, M is a permuation matrix/vector
sub map64(\s, \M) { my \b = h2bits s; map { b[$_-1] }, M; }
## Core subs
sub get_subkeys(Str \key --> Seq) { # return a Seq with 16 bit vectors
my \Kₚ = map64 key, PC1; # drop parity bits
my @C = Kₚ[0..27] ; my @D = Kₚ[28..55]; # perform bits rotation next
my \CD = map { [ flat @C ⥀= SHIFTS[$_], @D ⥀= SHIFTS[$_] ]}, ^16;
return map { map { CD[$_][PC2[$^a]-1] }, ^48 }, ^16; # key compression rounds
}
sub ƒ (List \R is copy, Seq \Kₙ is copy --> Seq) {
my @er = map { Kₙ[$_] +^ R[E[$_]-1] }, ^48;
my @sr = flat map { # Sₙ(Bₙ) loop, process @er six bits at a time
((S.[$_][([~] @er[$_*6,$_*6+5]).parse-base(2)*16+([~]
@er[$_*6+1 .. $_*6+4]).parse-base(2)]).fmt('%04b').split(""))[1..4]
}, ^8;
return map { @sr[$_-1] }, P;
}
sub process_block(Str \message, \K is copy --> Str) { # return 8 quadbits
my \mp = map64 (b2h message) , IP; # turn message to hex then map to bits
my @L = mp[0..31]; my @R = mp[32..63];
my (@Lₙ , @Rₙ); # then apply 16 iterations with function ƒ
{ @Lₙ = @R; @Rₙ = @L Z+^ ƒ @R, K[$_]; @L = @Lₙ; @R = @Rₙ } for ^16;
my \res = flat @R, @L; # reverse and join the final L₁₆ and R₁₆
return [~] map { res[$_-1] }, IP2 ; # inverse of the initial permutation
}
sub des(Str \key, Str $msg is copy, Bool \DECODE --> Str) { # return hexdecimal
my @K; my \length = $msg.encode('iso-8859-1').bytes;
if ( DECODE and length % 8 ) { # early exit, avoid the subkeys computation
die "Message must be in multiples of 8 bytes"
} else {
@K = DECODE ?? reverse get_subkeys key !! get_subkeys key
}
{ my \P = 8 - length % 8; # number of pad bytes
$msg ~= P.chr x P ; # CMS style padding as per RFC 1423 & RFC 5652
} unless DECODE;
 
my $quad ~= process_block substr($msg,$_,8), @K for
0, 8 … $msg.encode('iso-8859-1').bytes-8;
 
{ my @decrypt = q2b $quad; # quadbits to a byte code point list
@decrypt.pop xx @decrypt.tail; # remove padding
return b2h ( [~] map { .chr } , @decrypt )
} if DECODE ;
return q2h $quad
}
say "Encryption examples: ";
say des "133457799BBCDFF1", h2bytes("0123456789ABCDEF"), False;
say des "0E329232EA6D0D73", h2bytes("8787878787878787"), False;
say des "0E329232EA6D0D73", "Your lips are smoother than vaseline", False;
say des "0E329232EA6D0D73", "Your lips are smoother than vaseline\r\n", False;
say des "0E329232EA6D0D73", u2b("BMP: こんにちは ; Astral plane: 𝒳𝒴𝒵"), False;
say "Decryption examples: ";
say des "133457799BBCDFF1", h2bytes("85E813540F0AB405FDF2E174492922F8"), True;
say des "0E329232EA6D0D73", h2bytes("0000000000000000A913F4CB0BD30F97"), True;
say h2bytes des "0E329232EA6D0D73", h2bytes("C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F535849980A2E7453703513E"), True;
say h2bytes des "0E329232EA6D0D73", h2bytes("C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99"), True;
say h2u des "0E329232EA6D0D73", h2bytes("C040FB6A6E72D7C36D60CA9B9A35EB38D3194468AD808103C28E33AEF0B268D0E0366C160B028DDACF340003DCA8969343EBBD289DB94774"), True;</lang>
{{out}}
<pre>Encryption examples:
85E813540F0AB405FDF2E174492922F8
0000000000000000A913F4CB0BD30F97
C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F535849980A2E7453703513E
C0999FDDE378D7ED727DA00BCA5A84EE47F269A4D6438190D9D52F78F53584997F922CCB5B068D99
C040FB6A6E72D7C36D60CA9B9A35EB38D3194468AD808103C28E33AEF0B268D0E0366C160B028DDACF340003DCA8969343EBBD289DB94774
Decryption examples:
0123456789abcdef
8787878787878787
Your lips are smoother than vaseline
Your lips are smoother than vaseline
 
BMP: こんにちは ; Astral plane: 𝒳𝒴𝒵</pre>
 
=={{header|REXX}}==
Line 3,539:
}</lang>
{{Out}}See it running in your browser by [https://scastie.scala-lang.org/t6nGq1ebShKEA42LSIQ6Hg Scastie (JVM)].
 
=={{header|Symsyn}}==
<lang Symsyn>pc1 : 56
10,333

edits