1 /*
2 Copyright (c) 2011, Andre Somers
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in the
11       documentation and/or other materials provided with the distribution.
12     * Neither the name of the Rathenau Instituut, Andre Somers nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR #######; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #ifndef SIMPLECRYPT_H
29 #define SIMPLECRYPT_H
30 #include <QString>
31 #include <QVector>
32 #include <QFlags>
33 
34 /**
35   @short Simple encryption and decryption of strings and byte arrays
36 
37   This class provides a simple implementation of encryption and decryption
38   of strings and byte arrays.
39 
40   @warning The encryption provided by this class is NOT strong encryption. It may
41   help to shield things from curious eyes, but it will NOT stand up to someone
42   determined to break the encryption. Don't say you were not warned.
43 
44   The class uses a 64 bit key. Simply create an instance of the class, set the key,
45   and use the encryptToString() method to calculate an encrypted version of the input string.
46   To decrypt that string again, use an instance of SimpleCrypt initialized with
47   the same key, and call the decryptToString() method with the encrypted string. If the key
48   matches, the decrypted version of the string will be returned again.
49 
50   If you do not provide a key, or if something else is wrong, the encryption and
51   decryption function will return an empty string or will return a string containing nonsense.
52   lastError() will return a value indicating if the method was succesful, and if not, why not.
53 
54   SimpleCrypt is prepared for the case that the encryption and decryption
55   algorithm is changed in a later version, by prepending a version identifier to the cypertext.
56   */
57 class SimpleCrypt
58 {
59 public:
60     /**
61       CompressionMode describes if compression will be applied to the data to be
62       encrypted.
63       */
64     enum CompressionMode {
65         CompressionAuto,    /*!< Only apply compression if that results in a shorter plaintext. */
66         CompressionAlways,  /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */
67         CompressionNever    /*!< Never apply compression. */
68     };
69     /**
70       IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data
71       or wrong decryption keys.
72 
73       Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This
74       increases the length of the resulting cypertext, but makes it possible to check if the plaintext
75       appears to be valid after decryption.
76     */
77     enum IntegrityProtectionMode {
78         ProtectionNone,    /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */
79         ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */
80         ProtectionHash     /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */
81     };
82     /**
83       Error describes the type of error that occured.
84       */
85     enum Error {
86         ErrorNoError,         /*!< No error occurred. */
87         ErrorNoKeySet,        /*!< No key was set. You can not encrypt or decrypt without a valid key. */
88         ErrorUnknownVersion,  /*!< The version of this data is unknown, or the data is otherwise not valid. */
89         ErrorIntegrityFailed, /*!< The integrity check of the data failed. Perhaps the wrong key was used. */
90     };
91 
92     /**
93       Constructor.
94 
95       Constructs a SimpleCrypt instance without a valid key set on it.
96      */
97     SimpleCrypt();
98     /**
99       Constructor.
100 
101       Constructs a SimpleCrypt instance and initializes it with the given @arg key.
102      */
103     explicit SimpleCrypt(quint64 key);
104 
105     /**
106       (Re-) initializes the key with the given @arg key.
107       */
108     void setKey(quint64 key);
109     /**
110       Returns true if SimpleCrypt has been initialized with a key.
111       */
hasKey()112     bool hasKey() const {return !m_keyParts.isEmpty();}
113 
114     /**
115       Sets the compression mode to use when encrypting data. The default mode is Auto.
116 
117       Note that decryption is not influenced by this mode, as the decryption recognizes
118       what mode was used when encrypting.
119       */
setCompressionMode(CompressionMode mode)120     void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;}
121     /**
122       Returns the CompressionMode that is currently in use.
123       */
compressionMode()124     CompressionMode compressionMode() const {return m_compressionMode;}
125 
126     /**
127       Sets the integrity mode to use when encrypting data. The default mode is Checksum.
128 
129       Note that decryption is not influenced by this mode, as the decryption recognizes
130       what mode was used when encrypting.
131       */
setIntegrityProtectionMode(IntegrityProtectionMode mode)132     void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;}
133     /**
134       Returns the IntegrityProtectionMode that is currently in use.
135       */
integrityProtectionMode()136     IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;}
137 
138     /**
139       Returns the last error that occurred.
140       */
lastError()141     Error lastError() const {return m_lastError;}
142 
143     /**
144       Encrypts the @arg plaintext string with the key the class was initialized with, and returns
145       a cyphertext the result. The result is a base64 encoded version of the binary array that is the
146       actual result of the string, so it can be stored easily in a text format.
147       */
148     QString encryptToString(const QString& plaintext) ;
149     /**
150       Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns
151       a cyphertext the result. The result is a base64 encoded version of the binary array that is the
152       actual result of the encryption, so it can be stored easily in a text format.
153       */
154     QString encryptToString(QByteArray plaintext) ;
155     /**
156       Encrypts the @arg plaintext string with the key the class was initialized with, and returns
157       a binary cyphertext in a QByteArray the result.
158 
159       This method returns a byte array, that is useable for storing a binary format. If you need
160       a string you can store in a text file, use encryptToString() instead.
161       */
162     QByteArray encryptToByteArray(const QString& plaintext) ;
163     /**
164       Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns
165       a binary cyphertext in a QByteArray the result.
166 
167       This method returns a byte array, that is useable for storing a binary format. If you need
168       a string you can store in a text file, use encryptToString() instead.
169       */
170     QByteArray encryptToByteArray(QByteArray plaintext) ;
171 
172     /**
173       Decrypts a cyphertext string encrypted with this class with the set key back to the
174       plain text version.
175 
176       If an error occured, such as non-matching keys between encryption and decryption,
177       an empty string or a string containing nonsense may be returned.
178       */
179     QString decryptToString(const QString& cyphertext) ;
180     /**
181       Decrypts a cyphertext string encrypted with this class with the set key back to the
182       plain text version.
183 
184       If an error occured, such as non-matching keys between encryption and decryption,
185       an empty string or a string containing nonsense may be returned.
186       */
187     QByteArray decryptToByteArray(const QString& cyphertext) ;
188     /**
189       Decrypts a cyphertext binary encrypted with this class with the set key back to the
190       plain text version.
191 
192       If an error occured, such as non-matching keys between encryption and decryption,
193       an empty string or a string containing nonsense may be returned.
194       */
195     QString decryptToString(QByteArray cypher) ;
196     /**
197       Decrypts a cyphertext binary encrypted with this class with the set key back to the
198       plain text version.
199 
200       If an error occured, such as non-matching keys between encryption and decryption,
201       an empty string or a string containing nonsense may be returned.
202       */
203     QByteArray decryptToByteArray(QByteArray cypher) ;
204 
205     //enum to describe options that have been used for the encryption. Currently only one, but
206     //that only leaves room for future extensions like adding a cryptographic hash...
207     enum CryptoFlag{CryptoFlagNone = 0,
208                     CryptoFlagCompression = 0x01,
209                     CryptoFlagChecksum = 0x02,
210                     CryptoFlagHash = 0x04
211                    };
212     Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag);
213 private:
214 
215     void splitKey();
216 
217     quint64 m_key;
218     QVector<char> m_keyParts;
219     CompressionMode m_compressionMode;
220     IntegrityProtectionMode m_protectionMode;
221     Error m_lastError;
222 };
223 Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags)
224 
225 #endif // SimpleCrypt_H
226