1/*
2 * PROGRAM: Firebird samples.
3 * MODULE: DbCrypt.cpp
4 * DESCRIPTION: Sample of how diskcrypt may be written.
5 *
6 * The contents of this file are subject to the Initial
7 * Developer's Public License Version 1.0 (the "License");
8 * you may not use this file except in compliance with the
9 * License. You may obtain a copy of the License at
10 * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
11 *
12 * Software distributed under the License is distributed AS IS,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
14 * See the License for the specific language governing rights
15 * and limitations under the License.
16 *
17 * The Original Code was created by Alex Peshkov
18 * for the Firebird Open Source RDBMS project.
19 *
20 * Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
21 * and all contributors signed below.
22 *
23 * All Rights Reserved.
24 * Contributor(s): ______________________________________.
25 */
26
27#include "firebird.h"
28#include "firebird/Crypt.h"
29
30#include "../common/classes/fb_atomic.h"
31
32using namespace Firebird;
33
34namespace
35{
36
37IMaster* master = NULL;
38IPluginManager* pluginManager = NULL;
39
40class PluginModule : public IPluginModule
41{
42public:
43 PluginModule()
44 : flag(false)
45 { }
46
47 void registerMe()
48 {
49 pluginManager->registerModule(this);
50 flag = true;
51 }
52
53 ~PluginModule()
54 {
55 if (flag)
56 {
57 pluginManager->unregisterModule(this);
58 doClean();
59 }
60 }
61
62 int FB_CARG getVersion()
63 {
64 return FB_PLUGIN_MODULE_VERSION;
65 }
66
67 IPluginModule* FB_CARG getModule()
68 {
69 return this;
70 }
71
72 void FB_CARG doClean()
73 {
74 flag = false;
75 }
76
77private:
78 bool flag;
79};
80
81PluginModule module;
82
83class DbCrypt : public IDbCryptPlugin
84{
85public:
86 explicit DbCrypt(IPluginConfig* cnf)
87 : config(cnf), key(0), owner(NULL)
88 {
89 config->addRef();
90 }
91
92 ~DbCrypt()
93 {
94 config->release();
95 }
96
97 // ICryptPlugin implementation
98 void FB_CARG encrypt(IStatus* status, unsigned int length, const void* from, void* to);
99 void FB_CARG decrypt(IStatus* status, unsigned int length, const void* from, void* to);
100 void FB_CARG setKey(IStatus* status, unsigned int length, IKeyHolderPlugin** sources);
101
102 int FB_CARG release()
103 {
104 if (--refCounter == 0)
105 {
106 delete this;
107 return 0;
108 }
109 return 1;
110 }
111
112 void FB_CARG addRef()
113 {
114 ++refCounter;
115 }
116
117 int FB_CARG getVersion()
118 {
119 return FB_DBCRYPT_PLUGIN_VERSION;
120 }
121
122 IPluginModule* FB_CARG getModule()
123 {
124 return &module;
125 }
126
127 void FB_CARG setOwner(IRefCounted* o)
128 {
129 owner = o;
130 }
131
132 IRefCounted* FB_CARG getOwner()
133 {
134 return owner;
135 }
136
137private:
138 IPluginConfig* config;
139 UCHAR key;
140
141 AtomicCounter refCounter;
142 IRefCounted* owner;
143
144 void noKeyError(IStatus* status);
145};
146
147void DbCrypt::noKeyError(IStatus* status)
148{
149 ISC_STATUS_ARRAY vector;
150 vector[0] = isc_arg_gds;
151 vector[1] = isc_random;
152 vector[2] = isc_arg_string;
153 vector[3] = (ISC_STATUS)"Key not set";
154 vector[4] = isc_arg_end;
155 status->set(vector);
156}
157
158void FB_CARG DbCrypt::encrypt(IStatus* status, unsigned int length, const void* from, void* to)
159{
160 status->init();
161
162 if (!key)
163 {
164 noKeyError(status);
165 return;
166 }
167
168 const UCHAR* f = static_cast<const UCHAR*>(from);
169 UCHAR* t = static_cast<UCHAR*>(to);
170
171 while (length--)
172 {
173 *t++ = (*f++) + key;
174 }
175}
176
177void FB_CARG DbCrypt::decrypt(IStatus* status, unsigned int length, const void* from, void* to)
178{
179 status->init();
180
181 if (!key)
182 {
183 noKeyError(status);
184 return;
185 }
186
187 const UCHAR* f = static_cast<const UCHAR*>(from);
188 UCHAR* t = static_cast<UCHAR*>(to);
189
190 while (length--)
191 {
192 *t++ = (*f++) - key;
193 }
194}
195
196void FB_CARG DbCrypt::setKey(IStatus* status, unsigned int length, IKeyHolderPlugin** sources)
197{
198 status->init();
199
200 if (key != 0)
201 return;
202
203 IConfig* def = config->getDefaultConfig();
204 IConfigEntry* confEntry = def->find("Auto");
205 def->release();
206 if (confEntry)
207 {
208 char v = *(confEntry->getValue());
209 confEntry->release();
210 if (v == '1' || v == 'y' || v == 'Y' || v == 't' || v == 'T')
211 {
212 key = 0x5a;
213 return;
214 }
215 }
216
217 for (unsigned n = 0; n < length; ++n)
218 {
219 ICryptKeyCallback* callback = sources[n]->keyHandle(status, "sample");
220 if (!status->isSuccess())
221 {
222 return;
223 }
224
225 if (callback && callback->callback(0, NULL, 1, &key) == 1)
226 {
227 return;
228 }
229 }
230
231 key = 0;
232 noKeyError(status);
233}
234
235class Factory : public IPluginFactory
236{
237public:
238 int FB_CARG getVersion()
239 {
240 return FB_PLUGIN_FACTORY_VERSION;
241 }
242
243 IPluginModule* FB_CARG getModule()
244 {
245 return &module;
246 }
247
248 IPluginBase* FB_CARG createPlugin(IPluginConfig* factoryParameter)
249 {
250 DbCrypt* p = new DbCrypt(factoryParameter);
251 p->addRef();
252 return p;
253 }
254};
255
256Factory factory;
257
258} // anonymous namespace
259
260extern "C" void FB_PLUGIN_ENTRY_POINT(IMaster* m)
261{
262 master = m;
263 pluginManager = master->getPluginManager();
264
265 module.registerMe();
266 pluginManager->registerPluginFactory(PluginType::DbCrypt, "DbCrypt_example", &factory);
267}
268