ATLAS Offline Software
Loading...
Searching...
No Matches
SimpleEncrypter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// system include:
6#include <climits>
7#include <vector>
8#include <algorithm>
9#include <cstdlib>
10#include <ctime>
11#include <cmath>
12
13// ROOT includes
14#include <TString.h>
15
16// Local include(s):
18
19namespace xAOD {
20
21 //--------------------------------------------------------------------------
22 // Private static constants
23 //--------------------------------------------------------------------------
24 // This gives 0x10000 on a 64-bit platform.
25 // ??? Would probably be better to write these using bit operations,
26 // rather than FP, to avoid potential rounding issues.
27 // (eg. the maximum uint64_t cannot be represented exactly as a double)
29 (SimpleEncrypter::ULLI_t)pow(static_cast<double>(std::numeric_limits<ULLI_t>::max()), 0.25);
32 const unsigned int SimpleEncrypter::m_MAXHEXDIGITS =
33 (unsigned int)(log(pow(SimpleEncrypter::m_MAXRANGE,2))/log(16.))+3;
34
35 //--------------------------------------------------------------------------
36 // Public methods
37 //--------------------------------------------------------------------------
38
39 //--------------------------------------------------------------------------
40 // Constructor
41 //--------------------------------------------------------------------------
43 asg::AsgMessaging(name), m_n(0), m_e(0), m_d(0),
44 m_isOkForEnc(false), m_isOkForDec(false) {
45
46 // initialize random number generator
47 srand(static_cast<unsigned>(time(0)));
48 }
49
50 //--------------------------------------------------------------------------
51 // Destructor
52 //--------------------------------------------------------------------------
56
57 //--------------------------------------------------------------------------
58 // Generation of key pair as pair of hex strings
59 //--------------------------------------------------------------------------
60 std::pair<std::string, std::string> SimpleEncrypter::genKeyPair() {
61
62 // default preset
63 std::pair<std::string, std::string> keys =
64 std::make_pair("__NO_PRIV_KEY__", "__NO_PUB_KEY__");
65
66 // generate keys
68
69 if ( isOkForEnc() && isOkForDec() ) {
70 keys = std::make_pair(getPrivKey(), getPubKey());
71 }
72 return keys;
73 }
74
75 //--------------------------------------------------------------------------
76 // Set private key
77 //--------------------------------------------------------------------------
78 void SimpleEncrypter::setPrivKey(std::string keystr) {
79
80 std::pair<ULLI_t, ULLI_t> keys = decodeKeyString(std::move(keystr));
81
82 if ( m_n > 0 && m_n != keys.first ) {
83 ATH_MSG_WARNING("RSA module already set!");
84 }
85 m_n = keys.first;
86 m_d = keys.second;
87 m_isOkForDec = false;
88 }
89 //--------------------------------------------------------------------------
90 // Set public key
91 //--------------------------------------------------------------------------
92 void SimpleEncrypter::setPubKey(std::string keystr) {
93 std::pair<ULLI_t, ULLI_t> keys = decodeKeyString(std::move(keystr));
94 if ( m_n > 0 && m_n != keys.second ) {
95 ATH_MSG_WARNING("RSA module already set!");
96 }
97 m_e = keys.first;
98 m_n = keys.second;
99 m_isOkForEnc = false;
100 }
101 //--------------------------------------------------------------------------
102 // Get private key
103 //--------------------------------------------------------------------------
104 std::string SimpleEncrypter::getPrivKey() const {
105
106 return keyToString(m_n, m_d);
107 }
108 //--------------------------------------------------------------------------
109 // Get public key
110 //--------------------------------------------------------------------------
111 std::string SimpleEncrypter::getPubKey() const {
112
113 return keyToString(m_e, m_n);
114 }
115 //--------------------------------------------------------------------------
116 // Encrypt unsigned integer value
117 //--------------------------------------------------------------------------
119
120 ULLI_t b = a;
121
122 if ( isOkForEnc() ) {
123 b = encryptFPECycle(a);
124 }
125 return b;
126 }
127 //--------------------------------------------------------------------------
128 // Decrypt unsigned integer value
129 //--------------------------------------------------------------------------
131
132 ULLI_t b = a;
133
134 if ( isOkForDec() ) {
135 b = decryptFPECycle(a);
136 }
137 return b;
138 }
139 //--------------------------------------------------------------------------
140 // Encrypt positive float value
141 //--------------------------------------------------------------------------
143
144 float b = a;
145
146 if ( a > 0. ) {
147 if ( isOkForEnc() ) {
148 ULLI_t ia = floatBitsToInt(a);
149 ULLI_t ib = encryptFPECycle(ia);
150 b = intBitsToFloat(ib);
151 }
152 } else {
153 ATH_MSG_WARNING("Encrypt: Float value not positive: "
154 << a << Form(" (%a) !", a));
155 } // if a > 0
156 return b;
157 }
158
159 //--------------------------------------------------------------------------
160 // Decrypt positive float value
161 //--------------------------------------------------------------------------
163
164 float b = a;
165
166 // As nan is a valid encrypted value, decrypt it as well.
167 if ( a > 0. || std::isnan(a) ) {
168 if ( isOkForDec() ) {
169 ULLI_t ia = floatBitsToInt(a);
170 ULLI_t ib = decryptFPECycle(ia);
171 b = intBitsToFloat(ib);
172 }
173 } else {
174 ATH_MSG_WARNING("Decrypt: Float value not positive: "
175 << a << Form(" (%a) !", a));
176 } // if a > 0
177 return b;
178 }
179
180 //--------------------------------------------------------------------------
181 // Private methods
182 //--------------------------------------------------------------------------
183
184 //--------------------------------------------------------------------------
185 // Generate numeric representation of the keys
186 //--------------------------------------------------------------------------
188
189 // Generate prime numbers p != q
190 ULLI_t p(1);
191 ULLI_t q(1);
192 // Euler's phi function
193 ULLI_t phi(1);
194
195 // reset encryption and decryption exponent
196 m_e = 0;
197 m_d = 0;
198 while ( p == q || m_e < 2 || m_e >= phi || m_d < 2
199 || m_e*m_d % phi != 1 ) {
200 double dlog2 = 0.;
201 while ( p == q || dlog2 < 0.1 || dlog2 > 30. ) {
202 p = genPrime();
203 q = genPrime();
204 dlog2 = fabs(log2(p)-log2(q));
205 } // inner while loop
206 phi = (p-1)*(q-1);
207 m_n = p*q;
208 m_e = genCoprime(phi);
210 } // outer while loop
211 m_isOkForDec = false;
212 m_isOkForEnc = false;
213 }
214 //--------------------------------------------------------------------------
215 // Find a prime number
216 //--------------------------------------------------------------------------
218 //coverity[dont_call]
219 ULLI_t t = (m_MINRANGE + rand()) % (m_MAXRANGE-1);
220 do {
221 t++;
222 } while ( !isPrime(t) || t < m_MINRANGE );
223 return t;
224 }
225 //--------------------------------------------------------------------------
226 // Test for being a prime number
227 //--------------------------------------------------------------------------
229
230 bool isPrime = true;
231 if (n != 2) {
232 for (LLI_t i = 2; i < (LLI_t)sqrt(n) + 1; ++i) {
233 if (n % i == 0) {
234 isPrime = false;
235 break;
236 }
237 }
238 }
239 return isPrime;
240 }
241 //--------------------------------------------------------------------------
242 // Greatest common denominator
243 //--------------------------------------------------------------------------
246
247 std::vector<LLI_t> r;
248 LLI_t i = 1;
249 r.push_back(std::max(n1, n2));
250 r.push_back(std::min(n1, n2));
251 while (r[i] != 0) {
252 ++i;
253 r.push_back(r[i-2] % r[i-1]);
254 }
255 return r[i-1];
256 }
257 //--------------------------------------------------------------------------
258 // Find coprime number
259 //--------------------------------------------------------------------------
261
262 // make sure coprime is larger than 5th Fermat number (2^16+1 = 65537)
263 //coverity[dont_call]
264 ULLI_t i = (65537 + rand()) % (m_MAXRANGE -1);
265 do {
266 ++i;
267 } while (greatestCommonDenominator(n, i) != 1);
268 return i;
269 }
270 //--------------------------------------------------------------------------
271 // Find decryption exponent
272 //--------------------------------------------------------------------------
275
276 for (ULLI_t i=1; i<m_MAXRANGE; ++i) {
277 if ( ((phi * i + 1) % e) == 0 ) {
278 return (ULLI_t)((phi * i + 1) / e);
279 }
280 }
281 return 0;
282 }
283 //--------------------------------------------------------------------------
284 // Convert key to a hex string
285 //--------------------------------------------------------------------------
287
288 // length of keys w.r.t. hex digits
289 unsigned int ra = (unsigned int)(log(a)/log(16.))+1;
290 unsigned int rb = (unsigned int)(log(b)/log(16.))+1;
291
292 // random numbers for padding
293 //coverity[dont_call]
294 unsigned int r1 = rand() & ((1 << 4*(m_MAXHEXDIGITS-ra))-1);
295 //coverity[dont_call]
296 unsigned int r2 = rand() & ((1 << 4*(m_MAXHEXDIGITS-rb))-1);
297
298 // format string
299 TString tstr = Form("%02x%02x%02x%0*x%0*llx%0*x%0*llx",
300 m_MAXHEXDIGITS, ra, rb,
301 m_MAXHEXDIGITS-ra, r1, ra, a,
302 m_MAXHEXDIGITS-rb, r2, rb, b);
303
304 return std::string(tstr.Data());
305 }
306 //--------------------------------------------------------------------------
307 // Convert hex string to two integers
308 //--------------------------------------------------------------------------
309 std::pair<SimpleEncrypter::ULLI_t, SimpleEncrypter::ULLI_t>
310 SimpleEncrypter::decodeKeyString(std::string hstr) const {
311
312 std::pair<ULLI_t, ULLI_t> keys(0,0);
313
314 TString str(hstr);
315 if (str.IsHex() && str.Length() > 3) {
316 str.ToLower();
317 unsigned int ndigits = strtoul(TString(str(0,2)).Data(), nullptr, 16);
318 unsigned int ra = strtoul(TString(str(2,2)).Data(), nullptr, 16);
319 unsigned int rb = strtoul(TString(str(4,2)).Data(), nullptr, 16);
320 if ( str.Length() == (int)(2*ndigits + 6) ) {
321 keys.first = strtoll(TString(str(ndigits+6-ra, ra)).Data(),
322 nullptr, 16);
323 keys.second = strtoll(TString(str(2*ndigits+6-rb, rb)).Data(),
324 nullptr, 16);
325 } else {
326 ATH_MSG_ERROR("Private/public key must be a hex string of " <<
327 2*m_MAXHEXDIGITS+6 << " digits!");
328 } // if Length()
329 } else {
330 ATH_MSG_ERROR("Private/public key must be a hex string of " <<
331 2*m_MAXHEXDIGITS+6 << " digits!");
332 } // if IsHex() ...
333
334 return keys;
335 }
336 //--------------------------------------------------------------------------
337 // Interpret bits of positive floating point number as integer
338 //--------------------------------------------------------------------------
340
341 ULLI_t res(0);
342
343 if ( val < 0. ) {
344 ATH_MSG_ERROR("Float value needs to be positive!");
345 } else {
346 // convert floating point number to ULLI_t if size fits
347 if ( sizeof(float) <= sizeof(ULLI_t) ) {
348 // check whether a quick conversion is possible
349 if ( sizeof(float) == sizeof(int) ) {
350 union {
351 float f;
352 int i;
353 } fint;
354 fint.f = val;
355 res = fint.i;
356 } else {
357 // do a slow conversion
358 char* pval = reinterpret_cast<char*>(&val);
359 // loop over bytes
360 for (unsigned int i=0; i<sizeof(float); ++i) {
361 // loop over bits
362 for (unsigned int j=0; j<CHAR_BIT; ++j) {
363 unsigned int n = i*CHAR_BIT + j;
364 unsigned int bit = (*(pval+i) >> j) & 1;
365 if ( bit > 0 ) res |= 1 << n;
366 } // for bits
367 } // for bytes
368 } // if sizeof
369 } else {
370 ATH_MSG_ERROR("sizeof(float) > sizeof(ULLI_t): "
371 << sizeof(float) << " > " << sizeof(LLI_t));
372 } // if sizeof
373 } // if val < 0.
374
375 return res;
376 }
377 //--------------------------------------------------------------------------
378 // Interpret bits of positive integer as floating point number
379 //--------------------------------------------------------------------------
381
382 float res(0.);
383
384 // number of bits needed
385 unsigned int r = (int)(std::log2(val))+1;
386
387 // convert ULLI_t to floating point number if size fits
388 if ( sizeof(float)*CHAR_BIT >= r ) {
389 // check whether a quick conversion is possible
390 if ( sizeof(float) == sizeof(int) ) {
391 union {
392 float f;
393 ULLI_t i;
394 } ficnv;
395 ficnv.i = val;
396 res = ficnv.f;
397 } else {
398 // do a slow conversion
399 char* pres = reinterpret_cast<char*>(&res);
400 // loop over bytes
401 for (unsigned int i=0; i<sizeof(float); ++i) {
402 // loop over bits
403 for (unsigned int j=0; j<CHAR_BIT; ++j) {
404 unsigned int n = i*CHAR_BIT + j;
405 unsigned int bit = (val >> n) & 1;
406 if ( bit > 0 ) *(pres+i) |= 1 << j;
407 } // for bits
408 } // for bytes
409 } // if sizeof
410 } else {
411 ATH_MSG_WARNING("sizeof(float)*CHAR_BIT < r: "
412 << sizeof(float)*CHAR_BIT << " < " << r);
413 } // if sizeof
414
415 return res;
416 }
417 //--------------------------------------------------------------------------
418 // Encrypt using format preserving encryption w.r.t. RSA modulus
419 // via cycling
420 //--------------------------------------------------------------------------
422
423 ULLI_t enc = 0;
424 if ( a > 0 ) {
425 ULLI_t r = (int)(std::log2(m_n));
426 ULLI_t rmask = pow(2,r)-1;
427 ULLI_t c = a & rmask;
428 ULLI_t b = a - c;
429 do {
430 c = encryptInternal(c);
431 } while ( c > rmask );
432 enc = b + c;
433 } // if
434 return enc;
435 }
436 //--------------------------------------------------------------------------
437 // Decrypt using format preserving encryption w.r.t. RSA modulus
438 // via cycling
439 //--------------------------------------------------------------------------
441
442 ULLI_t dec = 0;
443 if ( enc > 0 ) {
444 ULLI_t r = (int)(std::log2(m_n));
445 ULLI_t rmask = pow(2,r)-1;
446 ULLI_t d = enc & rmask;
447 ULLI_t b = enc - d;
448 do {
449 d = decryptInternal(d);
450 } while ( d > rmask );
451 dec = d + b;
452 } // if
453 return dec;
454 }
455 //--------------------------------------------------------------------------
456 // Encrypt integer
457 //--------------------------------------------------------------------------
462 //--------------------------------------------------------------------------
463 // Decrypt integer
464 //--------------------------------------------------------------------------
469 //--------------------------------------------------------------------------
470 // Exponentiate a with d observing modulus n
471 //--------------------------------------------------------------------------
474
475 int bin[sizeof(ULLI_t)*CHAR_BIT];
476 ULLI_t dec[sizeof(ULLI_t)*CHAR_BIT];
477
478 ULLI_t r = (ULLI_t)(std::log2(d))+1;
479 ULLI_t tmp = d;
480 // decompose exponent into binary number (reverse order!)
481 for (ULLI_t i=0; i < r; ++i) {
482 bin[r-i-1] = tmp % 2;
483 tmp = (LLI_t)(tmp/2);
484 } // for i
485
486 // perform the exponentiation taking modulus into account
487 dec[0] = a;
488 for (ULLI_t i=1; i < r; ++i) {
489 ULLI_t d2 = dec[i-1]*dec[i-1] % n;
490 if ( bin[i] > 0 ) d2 *= a;
491 dec[i] = d2 % n;
492 } // for i
493
494 return dec[r-1];
495 }
496 //--------------------------------------------------------------------------
497 // Check setup readiness for encryption
498 //--------------------------------------------------------------------------
500
501 if ( !m_isOkForEnc ) {
502 if ( m_n > 0 && m_e > 1 && m_e < m_n ) {
503 m_isOkForEnc = true;
504 } else {
505 ATH_MSG_ERROR("Setup not OK for encryption: public key set?");
506 }
507 } // if ! m_isOkForEnc
508
509 return m_isOkForEnc;
510 }
511
512 //--------------------------------------------------------------------------
513 // Check setup readiness for decryption
514 //--------------------------------------------------------------------------
516
517 if ( !m_isOkForDec ) {
518 if ( m_n > 0 && m_d > 1 && m_d < m_n ) {
519 m_isOkForDec = true;
520 } else {
521 ATH_MSG_ERROR("Setup not OK for decryption: private key set?");
522 }
523 } // if ! m_isOkForDec
524
525 return m_isOkForDec;
526 }
527
528 //--------------------------------------------------------------------------
529} // namespace xAOD
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
@ Data
Definition BaseObject.h:11
std::pair< std::vector< unsigned int >, bool > res
static Double_t a
Provide simple asymmetric encryption for blinding of float values.
#define x
constexpr int pow(int base, int exp) noexcept
AsgMessaging(const std::string &name)
Constructor with a name.
ULLI_t powerMod(ULLI_t a, ULLI_t d, ULLI_t n) const
Exponentiate a with d observing modulus n.
ULLI_t encryptInternal(ULLI_t x) const
Encrypt integer (internal)
bool isOkForDec()
Check setup readiness for decryption.
bool m_isOkForEnc
indicates that keys are set and range checks are ok
virtual ULLI_t greatestCommonDenominator(ULLI_t n1, ULLI_t n2) const
Find greatest common denominator.
ULLI_t decryptInternal(ULLI_t x) const
Decrypt integer (internal)
ULLI_t decryptFPECycle(ULLI_t a) const
Decrypt using format preserving encryption w.r.t.
virtual void genKeyPairInternal()
virtual ULLI_t encrypt(ULLI_t x)
Encrypt a positive integer value.
virtual void setPrivKey(std::string keystr)
Set private key.
virtual ULLI_t decrypt(ULLI_t x)
Decrypt a positive integer value.
static const ULLI_t m_MAXRANGE
static const unsigned int m_MAXHEXDIGITS
maximum number of hex digits for key parts
unsigned long long int ULLI_t
virtual std::string getPrivKey() const
Get private key.
virtual ULLI_t genCoprime(ULLI_t n) const
Find a coprime number.
virtual void setPubKey(std::string keystr)
Set public key.
virtual std::string keyToString(ULLI_t a, ULLI_t b) const
static const ULLI_t m_MINRANGE
ULLI_t encryptFPECycle(ULLI_t a) const
virtual std::string getPubKey() const
Get public key.
virtual ULLI_t genPrime() const
Find a prime number.
bool isOkForEnc()
Check setup readiness for encryption.
virtual std::pair< std::string, std::string > genKeyPair()
Generate private and public keys.
ULLI_t m_e
encryption exponent: public key part II
SimpleEncrypter(const std::string &name="SimpleEncrypter")
Main constructor.
virtual ULLI_t genDecryptionExponent(ULLI_t phi, ULLI_t e) const
Find decryption exponent.
virtual float intBitsToFloat(ULLI_t val) const
Interpret bits of integer as floating point number.
ULLI_t m_d
decryption exponent: private key part II
virtual ~SimpleEncrypter()
Default destructor.
virtual std::pair< ULLI_t, ULLI_t > decodeKeyString(std::string str) const
Decode hex string to two integers.
long long int LLI_t
Useful typedefs.
virtual bool isPrime(ULLI_t n) const
Check for being a prime number.
virtual ULLI_t floatBitsToInt(float val) const
int r
Definition globals.cxx:22
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
setRawEt setRawPhi int