crypto-toolbox 0.0.16 → 0.1.0
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 +4 -4
- data/lib/crypto-toolbox/analyzers/vigenere_xor.rb +4 -2
- data/lib/crypto-toolbox/crypt_buffer.rb +164 -122
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8cd55faeae9f38185945c99d5b079a84ba2373f
|
4
|
+
data.tar.gz: db5ab428bd11e21c9fa9c4662b71c109e99d98f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80cb527eba8c5526e6e07cdf747f9426de16f3fb2cc694534b4d3bf4b7e4b3d4ee426bb3e24331204cf4ccad0546f91347e036851fbaada0ee47b49e5f51236e
|
7
|
+
data.tar.gz: c3d0d0be185630772ee9c30069881663bf4e94369e53212694881f23e38562d8955db2fd7c16dc19666242d933158c6cb99136c6e2c9bb439836d224a4c99398
|
@@ -16,12 +16,14 @@ module Analyzers
|
|
16
16
|
def print_delimiter_line
|
17
17
|
puts "====================================================================="
|
18
18
|
end
|
19
|
+
|
20
|
+
# Checks if a given byte maps to a reasonable english language character
|
19
21
|
def acceptable_char?(byte)
|
20
22
|
(byte > 31 && byte < 123) && (byte != 60 && byte !=64)
|
21
23
|
end
|
22
24
|
|
23
25
|
def find_pattern(buf)
|
24
|
-
bitstring = buf.nth_bits(
|
26
|
+
bitstring = buf.nth_bits(7).join("")
|
25
27
|
|
26
28
|
1.upto([buf.bytes.length,62].min).map do |ksize|
|
27
29
|
parts = bitstring.scan(/.{#{ksize}}/)
|
@@ -54,7 +56,7 @@ module Analyzers
|
|
54
56
|
|
55
57
|
candidate_map[key_byte]=[]
|
56
58
|
1.upto(255).each do |possible_key_value|
|
57
|
-
if smart_buf.xor_all_with(possible_key_value).bytes.all?{|byte|
|
59
|
+
if smart_buf.xor_all_with(possible_key_value).bytes.all?{|byte| acceptable_char?(byte) }
|
58
60
|
jot("YES: " + smart_buf.xor_all_with(possible_key_value).to_s,debug: true)
|
59
61
|
candidate_map[key_byte] << possible_key_value
|
60
62
|
else
|
@@ -2,151 +2,212 @@ require 'aes'
|
|
2
2
|
require 'openssl'
|
3
3
|
require 'forwardable'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module CryptBufferAspect
|
6
|
+
module Comparable
|
7
|
+
def ==(other)
|
8
|
+
bytes == bytes_from_any(other)
|
9
|
+
end
|
9
10
|
|
10
|
-
include Enumerable
|
11
|
-
extend ::Forwardable
|
12
|
-
def_delegators :@bytes, :[], :empty?,:include?, :length
|
13
|
-
|
14
|
-
def initialize(input)
|
15
|
-
@bytes = bytes_from_any(input)
|
16
11
|
end
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
module ByteExpander
|
14
|
+
private
|
15
|
+
def expand_bytes(input,total)
|
16
|
+
if input.length >= total
|
17
|
+
input
|
18
|
+
else
|
19
|
+
n = total / input.length
|
20
|
+
rest = total % input.length
|
21
|
+
|
22
|
+
# expand the input to the full length of the internal data
|
23
|
+
(input * n) + input[0,rest]
|
24
|
+
end
|
25
25
|
end
|
26
|
-
CryptBuffer.new(hexstr)
|
27
26
|
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
module Convertable
|
29
|
+
def hex
|
30
|
+
bytes2hex(bytes).upcase
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :h, :hex
|
34
|
+
|
35
|
+
def chars
|
36
|
+
map{|b| b.to_i.chr}
|
37
|
+
end
|
38
|
+
alias_method :c, :chars
|
39
|
+
|
40
|
+
def str
|
41
|
+
chars.join
|
42
|
+
end
|
43
|
+
alias_method :s, :str
|
32
44
|
|
33
|
-
|
45
|
+
def bits
|
46
|
+
map{|b| "%08d" % b.to_s(2) }
|
47
|
+
end
|
34
48
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
def to_s
|
50
|
+
str
|
51
|
+
end
|
52
|
+
private
|
53
|
+
def bytes2hex(bytes)
|
54
|
+
bytes.map{|b| b.to_s(16)}.map{|hs| hs.length == 1 ? "0#{hs}" : hs }.join
|
55
|
+
end
|
42
56
|
end
|
43
|
-
alias_method :c, :chars
|
44
57
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
58
|
+
module Xorable
|
59
|
+
|
60
|
+
def xor_at(input,pos)
|
61
|
+
return self if input.nil? || (pos.abs > length)
|
62
|
+
|
63
|
+
case input
|
64
|
+
when Array
|
65
|
+
# map our current data to xor all inputs with the given bytepos.
|
66
|
+
# all other bytes are kept as they were
|
67
|
+
tmp = bytes.map.with_index{|b,i| i == pos ? xor_multiple(b,input) : b }
|
68
|
+
CryptBuffer(tmp)
|
69
|
+
else
|
70
|
+
tmp = bytes
|
71
|
+
tmp[pos] = tmp[pos] ^ input
|
72
|
+
CryptBuffer(tmp)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def xor(input,expand_input: false)
|
77
|
+
if expand_input
|
78
|
+
xor_all_with(input)
|
79
|
+
else
|
80
|
+
xor_bytes(bytes_from_any(input))
|
81
|
+
end
|
82
|
+
end
|
49
83
|
|
84
|
+
def xor_all_with(input)
|
85
|
+
expanded = expand_bytes(bytes_from_any(input),self.bytes.length)
|
86
|
+
xor_bytes(expanded)
|
87
|
+
end
|
50
88
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
89
|
+
|
90
|
+
def xor_space
|
91
|
+
xor(0x20,expand_input: true)
|
92
|
+
end
|
93
|
+
private
|
55
94
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
95
|
+
def xor_bytes(byt)
|
96
|
+
len = [self.bytes.size,byt.size].min
|
97
|
+
result = self.bytes[0...len].map.with_index{|b,i| b ^ byt[i] } + self.bytes[len,self.bytes.length - len]
|
98
|
+
self.class.new(result)
|
99
|
+
end
|
100
|
+
|
101
|
+
def xor_hex(hex)
|
102
|
+
x = hex2bytes(hex)
|
103
|
+
xor_bytes(x)
|
104
|
+
end
|
62
105
|
|
63
|
-
def modulus(mod)
|
64
|
-
real_mod = sanitize_modulus(mod)
|
65
|
-
CryptBuffer( bytes.map{|b| b % real_mod } )
|
66
106
|
end
|
67
107
|
|
108
|
+
module ByteManipulation
|
109
|
+
|
110
|
+
def modulus(mod)
|
111
|
+
real_mod = sanitize_modulus(mod)
|
112
|
+
CryptBuffer( bytes.map{|b| b % real_mod } )
|
113
|
+
end
|
68
114
|
|
69
|
-
|
70
|
-
|
71
|
-
|
115
|
+
def mod_sub(n,mod: 256)
|
116
|
+
tmp = bytes.map do |byte|
|
117
|
+
val = byte.to_bn.mod_sub(n,mod).to_i
|
118
|
+
end
|
119
|
+
CryptBuffer(tmp)
|
72
120
|
end
|
73
|
-
CryptBuffer(tmp)
|
74
|
-
end
|
75
121
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
122
|
+
def sub(n)
|
123
|
+
CryptBuffer( bytes.map{|byte| byte -n } )
|
124
|
+
end
|
125
|
+
|
126
|
+
def add(n, mod: 256, offset: 0)
|
127
|
+
real_mod = [256,mod].min
|
81
128
|
|
82
|
-
|
83
|
-
|
84
|
-
|
129
|
+
tmp = bytes.map do |b|
|
130
|
+
val = (b + n) % real_mod
|
131
|
+
val >= offset ? val : val+offset
|
132
|
+
end
|
133
|
+
CryptBuffer(tmp)
|
85
134
|
end
|
86
|
-
CryptBuffer(tmp)
|
87
135
|
end
|
88
136
|
|
89
137
|
|
90
|
-
|
91
|
-
|
138
|
+
module PrettyPrint
|
139
|
+
def pp
|
140
|
+
puts pretty_hexstr
|
141
|
+
end
|
92
142
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
#
|
97
|
-
tmp = bytes.map.with_index{|b,i| i == pos ? xor_multiple(b,input) : b }
|
98
|
-
CryptBuffer(tmp)
|
99
|
-
else
|
100
|
-
tmp = bytes
|
101
|
-
tmp[pos] = tmp[pos] ^ input
|
102
|
-
CryptBuffer(tmp)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def xor(input,expand_input: false)
|
107
|
-
if expand_input
|
108
|
-
xor_all_with(input)
|
109
|
-
else
|
110
|
-
xor_bytes(bytes_from_any(input))
|
143
|
+
private
|
144
|
+
def pretty_hexstr
|
145
|
+
str = h.scan(/.{2}/).to_a.join(" ")
|
146
|
+
"0x#{h.upcase} (#{str.upcase})"
|
111
147
|
end
|
112
148
|
end
|
149
|
+
end
|
113
150
|
|
114
|
-
def xor_all_with(input)
|
115
|
-
expanded = expand_bytes(bytes_from_any(input),self.bytes.length)
|
116
|
-
xor_bytes(expanded)
|
117
|
-
end
|
118
151
|
|
119
|
-
|
120
|
-
|
152
|
+
|
153
|
+
class CryptBuffer
|
154
|
+
class OutOfRangeError < RuntimeError; end
|
155
|
+
|
156
|
+
|
157
|
+
include CryptBufferAspect::Convertable
|
158
|
+
include CryptBufferAspect::Comparable
|
159
|
+
include CryptBufferAspect::Xorable
|
160
|
+
include CryptBufferAspect::ByteManipulation
|
161
|
+
include CryptBufferAspect::PrettyPrint
|
162
|
+
include CryptBufferAspect::ByteExpander
|
163
|
+
|
164
|
+
extend Forwardable
|
165
|
+
def_delegators :@bytes, :[], :empty?,:include?, :length
|
166
|
+
|
167
|
+
|
168
|
+
attr_accessor :bytes
|
169
|
+
alias_method :b, :bytes
|
170
|
+
|
171
|
+
|
172
|
+
def initialize(input)
|
173
|
+
@bytes = bytes_from_any(input)
|
121
174
|
end
|
122
175
|
|
123
|
-
|
124
|
-
|
176
|
+
# Make sure input strings are always interpreted as hex strings
|
177
|
+
# This is especially useful for unknown or uncertain inputs like
|
178
|
+
# strings with or without leading 0x
|
179
|
+
def self.from_hex(input)
|
180
|
+
hexstr =""
|
181
|
+
unless input.nil?
|
182
|
+
hexstr = (input =~ /^0x/ ? input : "0x#{pad_hex_char(input)}" )
|
183
|
+
end
|
184
|
+
CryptBuffer.new(hexstr)
|
125
185
|
end
|
126
186
|
|
127
|
-
|
128
|
-
|
187
|
+
include Enumerable
|
188
|
+
def each(&block)
|
189
|
+
@bytes.each(&block)
|
129
190
|
end
|
130
191
|
|
131
|
-
|
132
|
-
|
192
|
+
|
193
|
+
# Returns an array of the nth least sigificant by bit of each byte
|
194
|
+
def nth_bits(n)
|
195
|
+
raise OutOfRangeError if n < 0
|
196
|
+
raise OutOfRangeError if n > 7
|
197
|
+
|
198
|
+
bits.map{|b| b.reverse[n].to_i }
|
199
|
+
end
|
200
|
+
|
201
|
+
def chunks_of(n)
|
202
|
+
self.bytes.each_slice(n).map{|chunk| CryptBuffer(chunk) }
|
133
203
|
end
|
134
204
|
|
205
|
+
|
135
206
|
private
|
136
207
|
def sanitize_modulus(mod)
|
137
208
|
(mod > 0) ? mod : 256
|
138
209
|
end
|
139
|
-
def expand_bytes(input,total)
|
140
|
-
if input.length >= total
|
141
|
-
input
|
142
|
-
else
|
143
|
-
n = total / input.length
|
144
|
-
rest = total % input.length
|
145
210
|
|
146
|
-
# expand the input to the full length of the internal data
|
147
|
-
(input * n) + input[0,rest]
|
148
|
-
end
|
149
|
-
end
|
150
211
|
def xor_multiple(byte,bytes)
|
151
212
|
([byte] + bytes).reduce(:^)
|
152
213
|
end
|
@@ -188,18 +249,6 @@ class CryptBuffer
|
|
188
249
|
raise "remove 0x from hexinput"
|
189
250
|
end
|
190
251
|
|
191
|
-
|
192
|
-
def xor_bytes(byt)
|
193
|
-
len = [self.bytes.size,byt.size].min
|
194
|
-
result = self.bytes[0...len].map.with_index{|b,i| b ^ byt[i] } + self.bytes[len,self.bytes.length - len]
|
195
|
-
CryptBuffer.new(result)
|
196
|
-
end
|
197
|
-
|
198
|
-
def xor_hex(hex)
|
199
|
-
x = hex2bytes(hex)
|
200
|
-
xor_bytes(x)
|
201
|
-
end
|
202
|
-
|
203
252
|
def hex2bytes(hexstr)
|
204
253
|
hexstr.scan(/../).map{|h| h.to_i(16) }
|
205
254
|
end
|
@@ -208,14 +257,7 @@ class CryptBuffer
|
|
208
257
|
str.bytes.to_a
|
209
258
|
end
|
210
259
|
|
211
|
-
def bytes2hex(bytes)
|
212
|
-
bytes.map{|b| b.to_s(16)}.map{|hs| hs.length == 1 ? "0#{hs}" : hs }.join
|
213
|
-
end
|
214
260
|
|
215
|
-
def pretty_hexstr
|
216
|
-
str = h.scan(/.{2}/).to_a.join(" ")
|
217
|
-
"0x#{h.upcase} (#{str.upcase})"
|
218
|
-
end
|
219
261
|
end
|
220
262
|
|
221
263
|
def CryptBuffer(input)
|