des 1.03
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/des.rb +111 -0
- data/lib/des/feistel.rb +70 -0
- data/lib/des/key_schedule.rb +40 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7510ef2176a3d24c508f769686a9431b2ea5c6d6
|
4
|
+
data.tar.gz: bbdc24272bd2ae1021d176e9533d93b9f85912a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c50ab8d64bc1c39f5de8ef51e9f94b77475fb8a44ee227f7e4d1e2d1b4e078125831bc9760ad2ea09dc970ba592bfbe79c2de26b36dd2597896481e1e20aac81
|
7
|
+
data.tar.gz: 319cbb98911b7fdb1a9544bebf76119e0af458fd44ec330cdec6210484b0090a2eb30d3fb270eb7f699692ff9c77c6686924c4212708fc81d04d327be0d64912
|
data/lib/des.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'des/feistel'
|
4
|
+
require 'des/key_schedule'
|
5
|
+
|
6
|
+
module DES
|
7
|
+
IP_L = [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]
|
8
|
+
IP_R = [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]
|
9
|
+
FP = [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,
|
10
|
+
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]
|
11
|
+
|
12
|
+
class ::Array
|
13
|
+
# @param [Array] another_ary
|
14
|
+
# @return [Array]
|
15
|
+
def xor(another_ary)
|
16
|
+
self.map.with_index { |obj, i| (obj ^ another_ary[i]) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Ctx
|
21
|
+
attr_reader :data, :key
|
22
|
+
|
23
|
+
def initialize(data, key)
|
24
|
+
unless data.is_a?(DES::Block) and key.is_a?(DES::Block)
|
25
|
+
raise 'DES::InvalidBlockFormat: Data and key must be a Block object.'
|
26
|
+
end
|
27
|
+
|
28
|
+
@data = data
|
29
|
+
@key = key
|
30
|
+
end
|
31
|
+
|
32
|
+
def encrypt
|
33
|
+
self.run(:encrypt)
|
34
|
+
end
|
35
|
+
|
36
|
+
def decrypt
|
37
|
+
self.run(:decrypt)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# @param [Symbol] operation
|
43
|
+
def run(operation)
|
44
|
+
# l[0] is the IP_1_L permutation of the data block, l[1..16] are the results of each round of encryption
|
45
|
+
l = []
|
46
|
+
# r[0] is the IP_1_R permutation of the data block, r[1..16] are the results of each round of encryption
|
47
|
+
r = []
|
48
|
+
|
49
|
+
l << IP_L.collect { |p| data.bit_array[p - 1] }
|
50
|
+
r << IP_R.collect { |p| data.bit_array[p - 1] }
|
51
|
+
|
52
|
+
case operation
|
53
|
+
when :encrypt
|
54
|
+
k = KeySchedule.new(key.bit_array).sub_keys
|
55
|
+
when :decrypt
|
56
|
+
k = KeySchedule.new(key.bit_array).sub_keys.reverse
|
57
|
+
else
|
58
|
+
raise "Unknown operation - #{operation}"
|
59
|
+
end
|
60
|
+
|
61
|
+
16.times do |i|
|
62
|
+
l << r[i]
|
63
|
+
r << Feistel.run(r[i], k[i]).xor(l[i])
|
64
|
+
end
|
65
|
+
|
66
|
+
DES::Block.new(FP.collect { |p| (r.last + l.last)[p - 1] })
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Block
|
71
|
+
attr_reader :string, :bit_array
|
72
|
+
|
73
|
+
alias_method :to_s, :string
|
74
|
+
alias_method :to_a, :bit_array
|
75
|
+
|
76
|
+
# @param [String, Array] input
|
77
|
+
# @return [NilClass]
|
78
|
+
def initialize(input)
|
79
|
+
if input.is_a?(String)
|
80
|
+
raise "DES::InvalidStringLength: Input String '#{input}' must contain (8) characters." unless input.length.eql?(8)
|
81
|
+
|
82
|
+
@string = input
|
83
|
+
@bit_array = input.unpack('B*').join.split('').collect { |b| b.to_i }
|
84
|
+
elsif input.is_a?(Array)
|
85
|
+
raise 'DES::InvalidArraySize: Input Array must contain (64) bits.' unless input.size.eql?(64)
|
86
|
+
|
87
|
+
@string = input.join.lines.to_a.pack('B*')
|
88
|
+
@bit_array = input
|
89
|
+
else
|
90
|
+
raise 'DES::InvalidFormat: Input must be a String or an Array.'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param [String, Array] data
|
96
|
+
# @param [String, Array] key
|
97
|
+
def self.encrypt(data, key)
|
98
|
+
data_block = DES::Block.new(data)
|
99
|
+
key_block = DES::Block.new(key)
|
100
|
+
|
101
|
+
DES::Ctx.new(data_block, key_block).encrypt
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param [DES::Block] data_block
|
105
|
+
# @param [String] key
|
106
|
+
def self.decrypt(data_block, key)
|
107
|
+
key_block = DES::Block.new(key)
|
108
|
+
DES::Ctx.new(data_block, key_block).decrypt
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
data/lib/des/feistel.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module Feistel
|
2
|
+
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,
|
3
|
+
21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1]
|
4
|
+
|
5
|
+
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,
|
6
|
+
4, 25]
|
7
|
+
|
8
|
+
S1 = [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,
|
9
|
+
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]
|
10
|
+
|
11
|
+
S2 = [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,
|
12
|
+
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]
|
13
|
+
|
14
|
+
S3 = [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,
|
15
|
+
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]
|
16
|
+
|
17
|
+
S4 = [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,
|
18
|
+
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]
|
19
|
+
|
20
|
+
S5 = [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,
|
21
|
+
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]
|
22
|
+
|
23
|
+
S6 = [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,
|
24
|
+
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]
|
25
|
+
|
26
|
+
S7 = [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,
|
27
|
+
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]
|
28
|
+
|
29
|
+
S8 = [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,
|
30
|
+
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]
|
31
|
+
|
32
|
+
S = [S1, S2, S3, S4, S5, S6, S7, S8]
|
33
|
+
|
34
|
+
# @param [Array] r
|
35
|
+
# @param [Array] k
|
36
|
+
def self.run(r, k)
|
37
|
+
# b[0..7] is e_xor_k prepped as 8 6-bit arrays for s-box substitution
|
38
|
+
b = []
|
39
|
+
# m[0..7] is the row of the value when performing a s-box lookup
|
40
|
+
m = []
|
41
|
+
# n[0..7] is the column of the value when performing a s-box lookup
|
42
|
+
n = []
|
43
|
+
|
44
|
+
# Expand r (right half data block) using E
|
45
|
+
e = E.collect { |p| r[p - 1] }
|
46
|
+
|
47
|
+
# X-or e (expanded r) with k (the sub key)
|
48
|
+
e_xor_k = e.xor(k)
|
49
|
+
|
50
|
+
# Break e_xor_k into 8 6-bit arrays and find both m (s-box row) and n (s-box column) for the s-box lookup
|
51
|
+
8.times do |i|
|
52
|
+
b << []
|
53
|
+
6.times do
|
54
|
+
b[i] << e_xor_k.shift
|
55
|
+
end
|
56
|
+
|
57
|
+
# [1, 0, 1, 0, 1, 0] => [1, 0] => 2 => 32 => 3rd row
|
58
|
+
m << [b[i].first, b[i].last].join.to_i(2) * 16
|
59
|
+
# [1, 0, 1, 0, 1, 0] => [0, 1, 0, 1] => 5 => 6th column
|
60
|
+
n << b[i][1..4].join.to_i(2)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Substitute every 6-bit array with the 4-bit array specified by the appropriate s-box
|
64
|
+
8.times do |i|
|
65
|
+
b[i] = S[i][m[i] + n[i]].to_s(2).rjust(4, '0').split('').collect { |bit| bit.to_i }
|
66
|
+
end
|
67
|
+
|
68
|
+
P.collect { |p| b.flatten[p - 1] }
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class KeySchedule
|
2
|
+
attr_accessor :sub_keys
|
3
|
+
attr_reader :key
|
4
|
+
|
5
|
+
PC_1_L = [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]
|
6
|
+
PC_1_R = [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]
|
7
|
+
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,
|
8
|
+
55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32]
|
9
|
+
|
10
|
+
ROTATIONS = [1, 1, 2, 2, 2, 2, 2, 2,
|
11
|
+
1, 2, 2, 2, 2, 2, 2, 1]
|
12
|
+
|
13
|
+
def initialize(key)
|
14
|
+
@key = key
|
15
|
+
|
16
|
+
# c[0] is the PC_1_L permutation of the key, c[1..16] are the results of each left shift.
|
17
|
+
c = []
|
18
|
+
# d[0] is the PC_1_R permutation of the key, d[1..16] are the results of each left shift.
|
19
|
+
d = []
|
20
|
+
# k[0..15] are the sub keys created by combining c[i] and d[i] and permuting with PC_2.
|
21
|
+
k = []
|
22
|
+
|
23
|
+
c << PC_1_L.collect { |p| key[p - 1] }
|
24
|
+
d << PC_1_R.collect { |p| key[p - 1] }
|
25
|
+
|
26
|
+
16.times do |i|
|
27
|
+
c << c[i]
|
28
|
+
d << d[i]
|
29
|
+
|
30
|
+
ROTATIONS[i].times do
|
31
|
+
c[i + 1] << c[i + 1].shift
|
32
|
+
d[i + 1] << d[i + 1].shift
|
33
|
+
end
|
34
|
+
|
35
|
+
k << PC_2.collect { |p| (c[i + 1] + d[i + 1])[p - 1] }
|
36
|
+
end
|
37
|
+
|
38
|
+
@sub_keys = k
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: des
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.03'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Sosinski
|
8
|
+
- Arthur Karganyan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-03 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: This gem make use DES Data Encryption.
|
15
|
+
email: dondenegocios@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/des.rb
|
21
|
+
- lib/des/feistel.rb
|
22
|
+
- lib/des/key_schedule.rb
|
23
|
+
homepage: https://github.com/dondenegocios/des
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.2.2
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: This gem make use DES Data Encryption.
|
47
|
+
test_files: []
|
48
|
+
has_rdoc:
|