Botan  1.11.15
src/lib/misc/aont/package.cpp
Go to the documentation of this file.
00001 /*
00002 * Rivest's Package Tranform
00003 *
00004 * (C) 2009 Jack Lloyd
00005 *
00006 * Botan is released under the Simplified BSD License (see license.txt)
00007 */
00008 
00009 #include <botan/package.h>
00010 #include <botan/filters.h>
00011 #include <botan/ctr.h>
00012 #include <botan/get_byte.h>
00013 #include <botan/internal/xor_buf.h>
00014 
00015 namespace Botan {
00016 
00017 void aont_package(RandomNumberGenerator& rng,
00018                   BlockCipher* cipher,
00019                   const byte input[], size_t input_len,
00020                   byte output[])
00021    {
00022    const size_t BLOCK_SIZE = cipher->block_size();
00023 
00024    if(!cipher->valid_keylength(BLOCK_SIZE))
00025       throw Invalid_Argument("AONT::package: Invalid cipher");
00026 
00027    // The all-zero string which is used both as the CTR IV and as K0
00028    const std::string all_zeros(BLOCK_SIZE*2, '0');
00029 
00030    SymmetricKey package_key(rng, BLOCK_SIZE);
00031 
00032    Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key));
00033 
00034    pipe.process_msg(input, input_len);
00035    pipe.read(output, pipe.remaining());
00036 
00037    // Set K0 (the all zero key)
00038    cipher->set_key(SymmetricKey(all_zeros));
00039 
00040    secure_vector<byte> buf(BLOCK_SIZE);
00041 
00042    const size_t blocks =
00043       (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE;
00044 
00045    byte* final_block = output + input_len;
00046    clear_mem(final_block, BLOCK_SIZE);
00047 
00048    // XOR the hash blocks into the final block
00049    for(size_t i = 0; i != blocks; ++i)
00050       {
00051       const size_t left = std::min<size_t>(BLOCK_SIZE,
00052                                            input_len - BLOCK_SIZE * i);
00053 
00054       zeroise(buf);
00055       copy_mem(&buf[0], output + (BLOCK_SIZE * i), left);
00056 
00057       for(size_t j = 0; j != sizeof(i); ++j)
00058          buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i);
00059 
00060       cipher->encrypt(&buf[0]);
00061 
00062       xor_buf(&final_block[0], &buf[0], BLOCK_SIZE);
00063       }
00064 
00065    // XOR the random package key into the final block
00066    xor_buf(&final_block[0], package_key.begin(), BLOCK_SIZE);
00067    }
00068 
00069 void aont_unpackage(BlockCipher* cipher,
00070                     const byte input[], size_t input_len,
00071                     byte output[])
00072    {
00073    const size_t BLOCK_SIZE = cipher->block_size();
00074 
00075    if(!cipher->valid_keylength(BLOCK_SIZE))
00076       throw Invalid_Argument("AONT::unpackage: Invalid cipher");
00077 
00078    if(input_len < BLOCK_SIZE)
00079       throw Invalid_Argument("AONT::unpackage: Input too short");
00080 
00081    // The all-zero string which is used both as the CTR IV and as K0
00082    const std::string all_zeros(BLOCK_SIZE*2, '0');
00083 
00084    cipher->set_key(SymmetricKey(all_zeros));
00085 
00086    secure_vector<byte> package_key(BLOCK_SIZE);
00087    secure_vector<byte> buf(BLOCK_SIZE);
00088 
00089    // Copy the package key (masked with the block hashes)
00090    copy_mem(&package_key[0],
00091             input + (input_len - BLOCK_SIZE),
00092             BLOCK_SIZE);
00093 
00094    const size_t blocks = ((input_len - 1) / BLOCK_SIZE);
00095 
00096    // XOR the blocks into the package key bits
00097    for(size_t i = 0; i != blocks; ++i)
00098       {
00099       const size_t left = std::min<size_t>(BLOCK_SIZE,
00100                                            input_len - BLOCK_SIZE * (i+1));
00101 
00102       zeroise(buf);
00103       copy_mem(&buf[0], input + (BLOCK_SIZE * i), left);
00104 
00105       for(size_t j = 0; j != sizeof(i); ++j)
00106          buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i);
00107 
00108       cipher->encrypt(&buf[0]);
00109 
00110       xor_buf(&package_key[0], &buf[0], BLOCK_SIZE);
00111       }
00112 
00113    Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key));
00114 
00115    pipe.process_msg(input, input_len - BLOCK_SIZE);
00116 
00117    pipe.read(output, pipe.remaining());
00118    }
00119 
00120 }