| 67 | | |
|---|
| 68 | | |
|---|
| 69 | | if __FILE__ == $0 |
|---|
| 70 | | include PGP |
|---|
| 71 | | require 'pgp/packet/tstbase' |
|---|
| 72 | | include Packet::TstBase |
|---|
| 73 | | |
|---|
| 74 | | require 'pgp/pkeyalgorithm' |
|---|
| 75 | | require 'pgp/mpi' |
|---|
| 76 | | require 'openssl' |
|---|
| 77 | | require 'pgp/hexdump' |
|---|
| 78 | | |
|---|
| 79 | | def cfb_encrypt(algo, key, data) |
|---|
| 80 | | header = Util.random_bytes(8) |
|---|
| 81 | | header << header[6, 2] |
|---|
| 82 | | cipher = OpenSSL::Cipher::Cipher.new(algo) |
|---|
| 83 | | cipher.key = key |
|---|
| 84 | | cipher.padding = 0 |
|---|
| 85 | | bs = 8 |
|---|
| 86 | | # step 1 |
|---|
| 87 | | fr = "\000" * bs |
|---|
| 88 | | # step 2 |
|---|
| 89 | | cipher.encrypt |
|---|
| 90 | | p fr |
|---|
| 91 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 92 | | # step 3 |
|---|
| 93 | | result = [] |
|---|
| 94 | | for i in 0..(bs - 1) do |
|---|
| 95 | | result << (fre[i] ^ header[i]) |
|---|
| 96 | | end |
|---|
| 97 | | # step 4 |
|---|
| 98 | | fr = result.pack("C*") |
|---|
| 99 | | # step 5 |
|---|
| 100 | | cipher.encrypt |
|---|
| 101 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 102 | | # step 6 |
|---|
| 103 | | result << (fre[0] ^ header[bs - 1]) |
|---|
| 104 | | result << (fre[1] ^ header[bs]) |
|---|
| 105 | | # step 7 |
|---|
| 106 | | fr = result.pack("C*")[2..-1] |
|---|
| 107 | | # step 8 |
|---|
| 108 | | cipher.encrypt |
|---|
| 109 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 110 | | # step 9 |
|---|
| 111 | | pos = 0 |
|---|
| 112 | | while pos < data.length |
|---|
| 113 | | for i in 0..(bs - 1) do |
|---|
| 114 | | break if data[pos].nil? |
|---|
| 115 | | result << (fre[i] ^ data[pos]) |
|---|
| 116 | | pos += 1 |
|---|
| 117 | | end |
|---|
| 118 | | # step 10 |
|---|
| 119 | | fr = result[(pos - bs) + bs + 2, bs].pack("C*") |
|---|
| 120 | | # step 11 |
|---|
| 121 | | cipher.encrypt |
|---|
| 122 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 123 | | end |
|---|
| 124 | | result.pack("C*") |
|---|
| 125 | | end |
|---|
| 126 | | |
|---|
| 127 | | def cfb_decrypt(algo, key, data) |
|---|
| 128 | | cipher = OpenSSL::Cipher::Cipher.new(algo) |
|---|
| 129 | | cipher.key = key |
|---|
| 130 | | cipher.padding = 0 |
|---|
| 131 | | header = data[0, 10] |
|---|
| 132 | | body = data[10..-1] |
|---|
| 133 | | bs = 8 |
|---|
| 134 | | # step 1 |
|---|
| 135 | | fr = "\000" * bs |
|---|
| 136 | | # step 2 |
|---|
| 137 | | cipher.encrypt |
|---|
| 138 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 139 | | # step 3 |
|---|
| 140 | | result = [] |
|---|
| 141 | | for i in 0..(bs - 1) do |
|---|
| 142 | | result << (fre[i] ^ header[i]) |
|---|
| 143 | | end |
|---|
| 144 | | # step 4 |
|---|
| 145 | | fr = header[0, bs] |
|---|
| 146 | | # step 5 |
|---|
| 147 | | cipher.encrypt |
|---|
| 148 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 149 | | # step 6 |
|---|
| 150 | | result << (fre[0] ^ header[bs - 1]) |
|---|
| 151 | | result << (fre[1] ^ header[bs]) |
|---|
| 152 | | # step 7 |
|---|
| 153 | | fr = header[2, bs] |
|---|
| 154 | | # step 8 |
|---|
| 155 | | cipher.encrypt |
|---|
| 156 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 157 | | # step 9 |
|---|
| 158 | | pos = 0 |
|---|
| 159 | | while pos < body.length |
|---|
| 160 | | for i in 0..(bs - 1) do |
|---|
| 161 | | break if body[pos].nil? |
|---|
| 162 | | result << (fre[i] ^ body[pos]) |
|---|
| 163 | | pos += 1 |
|---|
| 164 | | end |
|---|
| 165 | | # step 10 |
|---|
| 166 | | fr = body[(pos - bs), bs] |
|---|
| 167 | | # step 11 |
|---|
| 168 | | cipher.encrypt |
|---|
| 169 | | fre = cipher.update(fr); raise unless cipher.final.empty? |
|---|
| 170 | | end |
|---|
| 171 | | result.pack("C*")[10..-1] |
|---|
| 172 | | end |
|---|
| 173 | | |
|---|
| 174 | | def foo(key, lastiv, iv, unused, data) |
|---|
| 175 | | cipher = OpenSSL::Cipher::Cipher.new("DES-EDE3") |
|---|
| 176 | | cipher.key = key |
|---|
| 177 | | cipher.padding = 0 |
|---|
| 178 | | nbytes = data.size |
|---|
| 179 | | pos = 0 |
|---|
| 180 | | result = [] |
|---|
| 181 | | |
|---|
| 182 | | bs = 8 |
|---|
| 183 | | if nbytes <= unused |
|---|
| 184 | | raise |
|---|
| 185 | | end |
|---|
| 186 | | |
|---|
| 187 | | if unused > 0 |
|---|
| 188 | | nbytes -= unused |
|---|
| 189 | | for idx in 0..(unused-1) |
|---|
| 190 | | temp = data[pos]; pos += 1 |
|---|
| 191 | | result << (iv[idx + bs - unused] ^ temp) |
|---|
| 192 | | iv[idx + bs - unused] = temp |
|---|
| 193 | | end |
|---|
| 194 | | end |
|---|
| 195 | | |
|---|
| 196 | | while nbytes >= bs |
|---|
| 197 | | lastiv = iv.dup |
|---|
| 198 | | cipher.encrypt |
|---|
| 199 | | iv = cipher.update(iv); raise unless cipher.final.empty? |
|---|
| 200 | | for idx in 0..(bs-1) do |
|---|
| 201 | | temp = data[pos]; pos += 1 |
|---|
| 202 | | result << (iv[idx] ^ temp) |
|---|
| 203 | | iv[idx] = temp |
|---|
| 204 | | end |
|---|
| 205 | | nbytes -= bs |
|---|
| 206 | | end |
|---|
| 207 | | |
|---|
| 208 | | if nbytes > 0 |
|---|
| 209 | | lastiv = iv.dup |
|---|
| 210 | | cipher.encrypt |
|---|
| 211 | | iv = cipher.update(iv); raise unless cipher.final.empty? |
|---|
| 212 | | unused = bs - nbytes |
|---|
| 213 | | for idx in 0..(nbytes-1) do |
|---|
| 214 | | temp = data[pos]; pos += 1 |
|---|
| 215 | | result << (iv[idx] ^ temp) |
|---|
| 216 | | iv[idx] = temp |
|---|
| 217 | | end |
|---|
| 218 | | end |
|---|
| 219 | | return [result.pack("C*"), lastiv, iv, unused] |
|---|
| 220 | | end |
|---|
| 221 | | |
|---|
| 222 | | def cipher_sync(lastiv, iv, unused) |
|---|
| 223 | | bs = 8 |
|---|
| 224 | | if unused > 0 |
|---|
| 225 | | (lastiv + iv)[unused, bs] |
|---|
| 226 | | else |
|---|
| 227 | | raise |
|---|
| 228 | | end |
|---|
| 229 | | end |
|---|
| 230 | | |
|---|
| 231 | | text = "123456789" |
|---|
| 232 | | key2 = Util.random_bytes(24) |
|---|
| 233 | | cipher = cfb_encrypt("DES-EDE3", key2, text) |
|---|
| 234 | | plain = cfb_decrypt("DES-EDE3", key2, cipher) |
|---|
| 235 | | p [cipher, plain] |
|---|
| 236 | | #exit |
|---|
| 237 | | |
|---|
| 238 | | m = SEC_SUBKEY.decrypt(MSG_SESSKEY.sessionkey) |
|---|
| 239 | | alg, key = PKeyAlgorithm.decode_sessionkey(MPI.to_bytes(m)) |
|---|
| 240 | | msg = MSG_DATA.cipher |
|---|
| 241 | | puts HexDump.encode(key) |
|---|
| 242 | | |
|---|
| 243 | | p "--------" |
|---|
| 244 | | puts HexDump.encode(msg) |
|---|
| 245 | | puts HexDump.encode(cfb_decrypt("DES-EDE3", key2, msg)) |
|---|
| 246 | | p "--" |
|---|
| 247 | | |
|---|
| 248 | | #msg = cipher; key = key2 |
|---|
| 249 | | header = msg[0, 10] |
|---|
| 250 | | data = msg[10..-1] |
|---|
| 251 | | |
|---|
| 252 | | lastiv = iv = "\000" * 8 |
|---|
| 253 | | unused = 0 |
|---|
| 254 | | result1, lastiv, iv, unused = foo(key, lastiv, iv, unused, header) |
|---|
| 255 | | lastiv = iv |
|---|
| 256 | | # Unlike the Symmetrically Encrypted Data Packet, no special CFB |
|---|
| 257 | | # resynchronization is done after encrypting this prefix data. |
|---|
| 258 | | #iv = cipher_sync(lastiv, iv, unused) |
|---|
| 259 | | #unused = 0 |
|---|
| 260 | | result2, lastiv, iv, unused = foo(key, lastiv, iv, unused, data) |
|---|
| 261 | | puts HexDump.encode(result1 + result2) |
|---|
| 262 | | p "-" |
|---|
| 263 | | cipher = OpenSSL::Cipher::Cipher.new("DES-EDE3-CFB") |
|---|
| 264 | | cipher.decrypt |
|---|
| 265 | | cipher.key = key |
|---|
| 266 | | cipher.iv = "\000" * 8 |
|---|
| 267 | | cipher.padding = 0 |
|---|
| 268 | | puts HexDump.encode(cipher.update(msg) + cipher.final) |
|---|
| 269 | | |
|---|
| 270 | | target = result2[0, result2.size - 20] |
|---|
| 271 | | mdc = result2[-20..-1] |
|---|
| 272 | | if Digest::SHA1.digest(result1 + target) != mdc |
|---|
| 273 | | raise "MDC check failed" |
|---|
| 274 | | end |
|---|
| 275 | | require 'zlib' |
|---|
| 276 | | z = Zlib::Inflate.new(-15) |
|---|
| 277 | | p "--" |
|---|
| 278 | | puts HexDump.encode(z.inflate(target[2..-1]) + z.finish) |
|---|
| 279 | | |
|---|
| 280 | | p "/////" |
|---|
| 281 | | |
|---|
| 282 | | m = SEC_SUBKEY.decrypt(MSG_SESSKEY.sessionkey) |
|---|
| 283 | | algo, key = PKeyAlgorithm.decode_sessionkey(MPI.to_bytes(m)) |
|---|
| 284 | | MSG_DATA.decrypt(algo, key) |
|---|
| 285 | | com = PGP::Packet::Packet.load(MSG_DATA.plain) |
|---|
| 286 | | lit = com[0].body |
|---|
| 287 | | p PGP::Packet::Packet.load(lit) |
|---|
| 288 | | puts PGP::Packet::Packet.load(lit)[0].body |
|---|
| 289 | | end |
|---|