summaryrefslogtreecommitdiff
path: root/mysql/extra/yassl/taocrypt/include/modes.hpp
blob: bfe8c6ec5d45bc6af6939220d0576e976d39b320 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
   Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING. If not, write to the
   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   MA  02110-1301  USA.
*/

/* modes.hpp provides ECB and CBC modes for block cipher encryption/decryption
*/


#ifndef TAO_CRYPT_MODES_HPP
#define TAO_CRYPT_MODES_HPP

#include "misc.hpp"

namespace TaoCrypt {


enum Mode { ECB, CBC };



// BlockCipher abstraction
template<CipherDir DIR, class T, Mode MODE>
class BlockCipher {
public:
    BlockCipher() : cipher_(DIR, MODE) {}

    void Process(byte* c, const byte* p, word32 sz) 
            { cipher_.Process(c, p, sz); }
    void SetKey(const byte* k, word32 sz)   
            { cipher_.SetKey(k, sz, DIR); }
    void SetKey(const byte* k, word32 sz, const byte* iv)   
            { cipher_.SetKey(k, sz, DIR); cipher_.SetIV(iv); }
private:
    T cipher_;

    BlockCipher(const BlockCipher&);            // hide copy
    BlockCipher& operator=(const BlockCipher&); // and assign
};


// Mode Base for block ciphers, static size
class Mode_BASE : public virtual_base {
public:
    enum { MaxBlockSz = 16 };

    explicit Mode_BASE(int sz, CipherDir dir, Mode mode) 
        : blockSz_(sz), reg_(reinterpret_cast<byte*>(r_)),
          tmp_(reinterpret_cast<byte*>(t_)), dir_(dir), mode_(mode)
    {}
    virtual ~Mode_BASE() {}

    virtual void Process(byte*, const byte*, word32);

    void SetIV(const byte* iv) { memcpy(reg_, iv, blockSz_); }
protected:
    int   blockSz_;
    byte* reg_;
    byte* tmp_;

    word32 r_[MaxBlockSz / sizeof(word32)];  // align reg_ on word32
    word32 t_[MaxBlockSz / sizeof(word32)];  // align tmp_ on word32

    CipherDir dir_;
    Mode      mode_;

    void ECB_Process(byte*, const byte*, word32);
    void CBC_Encrypt(byte*, const byte*, word32);
    void CBC_Decrypt(byte*, const byte*, word32);

    Mode_BASE(const Mode_BASE&);            // hide copy
    Mode_BASE& operator=(const Mode_BASE&); // and assign

private:
    virtual void ProcessAndXorBlock(const byte*, const byte*, byte*) const = 0;
};


inline void Mode_BASE::Process(byte* out, const byte* in, word32 sz)
{
    if (mode_ == ECB)
        ECB_Process(out, in, sz);
    else if (mode_ == CBC) {
        if (dir_ == ENCRYPTION)
            CBC_Encrypt(out, in, sz);
        else
            CBC_Decrypt(out, in, sz);
    }
}


// ECB Process blocks
inline void Mode_BASE::ECB_Process(byte* out, const byte* in, word32 sz)
{
    word32 blocks = sz / blockSz_;

    while (blocks--) {
        ProcessAndXorBlock(in, 0, out);
        out += blockSz_;
        in  += blockSz_;
    }
}


// CBC Encrypt
inline void Mode_BASE::CBC_Encrypt(byte* out, const byte* in, word32 sz)
{
    word32 blocks = sz / blockSz_;

    while (blocks--) {
        xorbuf(reg_, in, blockSz_);
        ProcessAndXorBlock(reg_, 0, reg_);
        memcpy(out, reg_, blockSz_);
        out += blockSz_;
        in  += blockSz_;
    }
}


// CBC Decrypt
inline void Mode_BASE::CBC_Decrypt(byte* out, const byte* in, word32 sz)
{
    word32 blocks = sz / blockSz_;
    byte   hold[MaxBlockSz];

    while (blocks--) {
        memcpy(tmp_, in, blockSz_);
        ProcessAndXorBlock(tmp_, 0, out);
        xorbuf(out,  reg_, blockSz_);
        memcpy(hold, reg_,   blockSz_); // swap reg_ and tmp_
        memcpy(reg_,   tmp_, blockSz_);
        memcpy(tmp_, hold, blockSz_);
        out += blockSz_;
        in  += blockSz_;
    }
}


} // namespace

#endif  // TAO_CRYPT_MODES_HPP