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
6// Local include(s):
8// ROOT includes
9#include <TString.h>
10
11// system include:
12#include <vector>
13#include <algorithm>
14#include <cstdlib>
15#include <ctime>
16#include <cmath>
17#include <bit>
18#include <cstdint>
19#include <limits>
20
21
22
23
24
25namespace xAOD {
26
27 //--------------------------------------------------------------------------
28 // Private static constants
29 //--------------------------------------------------------------------------
30 // This gives 0x10000 on a 64-bit platform.
31 // ??? Would probably be better to write these using bit operations,
32 // rather than FP, to avoid potential rounding issues.
33 // (eg. the maximum uint64_t cannot be represented exactly as a double)
35 (SimpleEncrypter::ULLI_t)pow(static_cast<double>(std::numeric_limits<ULLI_t>::max()), 0.25);
38 const unsigned int SimpleEncrypter::m_MAXHEXDIGITS =
39 (unsigned int)(log(pow(SimpleEncrypter::m_MAXRANGE,2))/log(16.))+3;
40
41 //--------------------------------------------------------------------------
42 // Public methods
43 //--------------------------------------------------------------------------
44
45 //--------------------------------------------------------------------------
46 // Constructor
47 //--------------------------------------------------------------------------
49 asg::AsgMessaging(name), m_n(0), m_e(0), m_d(0),
50 m_isOkForEnc(false), m_isOkForDec(false) {
51
52 // initialize random number generator
53 srand(static_cast<unsigned>(time(0)));
54 }
55
56 //--------------------------------------------------------------------------
57 // Destructor
58 //--------------------------------------------------------------------------
62
63 //--------------------------------------------------------------------------
64 // Generation of key pair as pair of hex strings
65 //--------------------------------------------------------------------------
66 std::pair<std::string, std::string> SimpleEncrypter::genKeyPair() {
67
68 // default preset
69 std::pair<std::string, std::string> keys =
70 std::make_pair("__NO_PRIV_KEY__", "__NO_PUB_KEY__");
71
72 // generate keys
74
75 if ( isOkForEnc() && isOkForDec() ) {
76 keys = std::make_pair(getPrivKey(), getPubKey());
77 }
78 return keys;
79 }
80
81 //--------------------------------------------------------------------------
82 // Set private key
83 //--------------------------------------------------------------------------
84 void SimpleEncrypter::setPrivKey(std::string keystr) {
85
86 std::pair<ULLI_t, ULLI_t> keys = decodeKeyString(std::move(keystr));
87
88 if ( m_n > 0 && m_n != keys.first ) {
89 ATH_MSG_WARNING("RSA module already set!");
90 }
91 m_n = keys.first;
92 m_d = keys.second;
93 m_isOkForDec = false;
94 }
95 //--------------------------------------------------------------------------
96 // Set public key
97 //--------------------------------------------------------------------------
98 void SimpleEncrypter::setPubKey(std::string keystr) {
99 std::pair<ULLI_t, ULLI_t> keys = decodeKeyString(std::move(keystr));
100 if ( m_n > 0 && m_n != keys.second ) {
101 ATH_MSG_WARNING("RSA module already set!");
102 }
103 m_e = keys.first;
104 m_n = keys.second;
105 m_isOkForEnc = false;
106 }
107 //--------------------------------------------------------------------------
108 // Get private key
109 //--------------------------------------------------------------------------
110 std::string SimpleEncrypter::getPrivKey() const {
111
112 return keyToString(m_n, m_d);
113 }
114 //--------------------------------------------------------------------------
115 // Get public key
116 //--------------------------------------------------------------------------
117 std::string SimpleEncrypter::getPubKey() const {
118
119 return keyToString(m_e, m_n);
120 }
121 //--------------------------------------------------------------------------
122 // Encrypt unsigned integer value
123 //--------------------------------------------------------------------------
125
126 ULLI_t b = a;
127
128 if ( isOkForEnc() ) {
129 b = encryptFPECycle(a);
130 }
131 return b;
132 }
133 //--------------------------------------------------------------------------
134 // Decrypt unsigned integer value
135 //--------------------------------------------------------------------------
137
138 ULLI_t b = a;
139
140 if ( isOkForDec() ) {
141 b = decryptFPECycle(a);
142 }
143 return b;
144 }
145 //--------------------------------------------------------------------------
146 // Encrypt positive float value
147 //--------------------------------------------------------------------------
149
150 float b = a;
151
152 if ( a > 0. ) {
153 if ( isOkForEnc() ) {
154 ULLI_t ia = floatBitsToInt(a);
155 ULLI_t ib = encryptFPECycle(ia);
156 b = intBitsToFloat(ib);
157 }
158 } else {
159 ATH_MSG_WARNING("Encrypt: Float value not positive: "
160 << a << Form(" (%a) !", a));
161 } // if a > 0
162 return b;
163 }
164
165 //--------------------------------------------------------------------------
166 // Decrypt positive float value
167 //--------------------------------------------------------------------------
169
170 float b = a;
171
172 // As nan is a valid encrypted value, decrypt it as well.
173 if ( a > 0. || std::isnan(a) ) {
174 if ( isOkForDec() ) {
175 ULLI_t ia = floatBitsToInt(a);
176 ULLI_t ib = decryptFPECycle(ia);
177 b = intBitsToFloat(ib);
178 }
179 } else {
180 ATH_MSG_WARNING("Decrypt: Float value not positive: "
181 << a << Form(" (%a) !", a));
182 } // if a > 0
183 return b;
184 }
185
186 //--------------------------------------------------------------------------
187 // Private methods
188 //--------------------------------------------------------------------------
189
190 //--------------------------------------------------------------------------
191 // Generate numeric representation of the keys
192 //--------------------------------------------------------------------------
194
195 // Generate prime numbers p != q
196 ULLI_t p(1);
197 ULLI_t q(1);
198 // Euler's phi function
199 ULLI_t phi(1);
200
201 // reset encryption and decryption exponent
202 m_e = 0;
203 m_d = 0;
204 while ( p == q || m_e < 2 || m_e >= phi || m_d < 2
205 || m_e*m_d % phi != 1 ) {
206 double dlog2 = 0.;
207 while ( p == q || dlog2 < 0.1 || dlog2 > 30. ) {
208 p = genPrime();
209 q = genPrime();
210 dlog2 = fabs(log2(p)-log2(q));
211 } // inner while loop
212 phi = (p-1)*(q-1);
213 m_n = p*q;
214 m_e = genCoprime(phi);
216 } // outer while loop
217 m_isOkForDec = false;
218 m_isOkForEnc = false;
219 }
220 //--------------------------------------------------------------------------
221 // Find a prime number
222 //--------------------------------------------------------------------------
224 //coverity[dont_call]
225 ULLI_t t = (m_MINRANGE + rand()) % (m_MAXRANGE-1);
226 do {
227 t++;
228 } while ( !isPrime(t) || t < m_MINRANGE );
229 return t;
230 }
231 //--------------------------------------------------------------------------
232 // Test for being a prime number
233 //--------------------------------------------------------------------------
235
236 bool isPrime = true;
237 if (n != 2) {
238 for (LLI_t i = 2; i < (LLI_t)sqrt(n) + 1; ++i) {
239 if (n % i == 0) {
240 isPrime = false;
241 break;
242 }
243 }
244 }
245 return isPrime;
246 }
247 //--------------------------------------------------------------------------
248 // Greatest common denominator
249 //--------------------------------------------------------------------------
252
253 std::vector<LLI_t> r;
254 LLI_t i = 1;
255 r.push_back(std::max(n1, n2));
256 r.push_back(std::min(n1, n2));
257 while (r[i] != 0) {
258 ++i;
259 r.push_back(r[i-2] % r[i-1]);
260 }
261 return r[i-1];
262 }
263 //--------------------------------------------------------------------------
264 // Find coprime number
265 //--------------------------------------------------------------------------
267
268 // make sure coprime is larger than 5th Fermat number (2^16+1 = 65537)
269 //coverity[dont_call]
270 ULLI_t i = (65537 + rand()) % (m_MAXRANGE -1);
271 do {
272 ++i;
273 } while (greatestCommonDenominator(n, i) != 1);
274 return i;
275 }
276 //--------------------------------------------------------------------------
277 // Find decryption exponent
278 //--------------------------------------------------------------------------
281
282 for (ULLI_t i=1; i<m_MAXRANGE; ++i) {
283 if ( ((phi * i + 1) % e) == 0 ) {
284 return (ULLI_t)((phi * i + 1) / e);
285 }
286 }
287 return 0;
288 }
289 //--------------------------------------------------------------------------
290 // Convert key to a hex string
291 //--------------------------------------------------------------------------
293
294 // length of keys w.r.t. hex digits
295 unsigned int ra = (unsigned int)(log(a)/log(16.))+1;
296 unsigned int rb = (unsigned int)(log(b)/log(16.))+1;
297
298 // random numbers for padding
299 //coverity[dont_call]
300 unsigned int r1 = rand() & ((1 << 4*(m_MAXHEXDIGITS-ra))-1);
301 //coverity[dont_call]
302 unsigned int r2 = rand() & ((1 << 4*(m_MAXHEXDIGITS-rb))-1);
303
304 // format string
305 TString tstr = Form("%02x%02x%02x%0*x%0*llx%0*x%0*llx",
306 m_MAXHEXDIGITS, ra, rb,
307 m_MAXHEXDIGITS-ra, r1, ra, a,
308 m_MAXHEXDIGITS-rb, r2, rb, b);
309
310 return std::string(tstr.Data());
311 }
312 //--------------------------------------------------------------------------
313 // Convert hex string to two integers
314 //--------------------------------------------------------------------------
315 std::pair<SimpleEncrypter::ULLI_t, SimpleEncrypter::ULLI_t>
316 SimpleEncrypter::decodeKeyString(std::string hstr) const {
317
318 std::pair<ULLI_t, ULLI_t> keys(0,0);
319
320 TString str(hstr);
321 if (str.IsHex() && str.Length() > 3) {
322 str.ToLower();
323 unsigned int ndigits = strtoul(TString(str(0,2)).Data(), nullptr, 16);
324 unsigned int ra = strtoul(TString(str(2,2)).Data(), nullptr, 16);
325 unsigned int rb = strtoul(TString(str(4,2)).Data(), nullptr, 16);
326 if ( str.Length() == (int)(2*ndigits + 6) ) {
327 keys.first = strtoll(TString(str(ndigits+6-ra, ra)).Data(),
328 nullptr, 16);
329 keys.second = strtoll(TString(str(2*ndigits+6-rb, rb)).Data(),
330 nullptr, 16);
331 } else {
332 ATH_MSG_ERROR("Private/public key must be a hex string of " <<
333 2*m_MAXHEXDIGITS+6 << " digits!");
334 } // if Length()
335 } else {
336 ATH_MSG_ERROR("Private/public key must be a hex string of " <<
337 2*m_MAXHEXDIGITS+6 << " digits!");
338 } // if IsHex() ...
339
340 return keys;
341 }
342 //--------------------------------------------------------------------------
343 // Interpret bits of positive floating point number as integer
344 //--------------------------------------------------------------------------
347 static_assert(sizeof(float) == sizeof(std::uint32_t),"This code assumes a 32-bit float");
348 if (val < 0.0F) {
349 ATH_MSG_ERROR("Float value needs to be positive!");
350 return 0;
351 }
352 return std::bit_cast<std::uint32_t>(val);
353 }
354 //--------------------------------------------------------------------------
355 // Interpret bits of positive integer as floating point number
356 //--------------------------------------------------------------------------
357 float
359 static_assert(sizeof(float) == sizeof(std::uint32_t),"This code assumes a 32-bit float");
360 if (val > std::numeric_limits<std::uint32_t>::max()) {
361 ATH_MSG_WARNING("Value does not fit in float bit representation: "<< val);
362 return 0.0F;
363 }
364 return std::bit_cast<float>(static_cast<std::uint32_t>(val));
365 }
366 //--------------------------------------------------------------------------
367 // Encrypt using format preserving encryption w.r.t. RSA modulus
368 // via cycling
369 //--------------------------------------------------------------------------
371
372 ULLI_t enc = 0;
373 if ( a > 0 ) {
374 ULLI_t r = (int)(std::log2(m_n));
375 ULLI_t rmask = pow(2,r)-1;
376 ULLI_t c = a & rmask;
377 ULLI_t b = a - c;
378 do {
379 c = encryptInternal(c);
380 } while ( c > rmask );
381 enc = b + c;
382 } // if
383 return enc;
384 }
385 //--------------------------------------------------------------------------
386 // Decrypt using format preserving encryption w.r.t. RSA modulus
387 // via cycling
388 //--------------------------------------------------------------------------
390
391 ULLI_t dec = 0;
392 if ( enc > 0 ) {
393 ULLI_t r = (int)(std::log2(m_n));
394 ULLI_t rmask = pow(2,r)-1;
395 ULLI_t d = enc & rmask;
396 ULLI_t b = enc - d;
397 do {
398 d = decryptInternal(d);
399 } while ( d > rmask );
400 dec = d + b;
401 } // if
402 return dec;
403 }
404 //--------------------------------------------------------------------------
405 // Encrypt integer
406 //--------------------------------------------------------------------------
411 //--------------------------------------------------------------------------
412 // Decrypt integer
413 //--------------------------------------------------------------------------
418 //--------------------------------------------------------------------------
419 // Exponentiate a with d observing modulus n
420 //--------------------------------------------------------------------------
423
424 int bin[sizeof(ULLI_t)*CHAR_BIT];
425 ULLI_t dec[sizeof(ULLI_t)*CHAR_BIT];
426
427 ULLI_t r = (ULLI_t)(std::log2(d))+1;
428 ULLI_t tmp = d;
429 // decompose exponent into binary number (reverse order!)
430 for (ULLI_t i=0; i < r; ++i) {
431 bin[r-i-1] = tmp % 2;
432 tmp = (LLI_t)(tmp/2);
433 } // for i
434
435 // perform the exponentiation taking modulus into account
436 dec[0] = a;
437 for (ULLI_t i=1; i < r; ++i) {
438 ULLI_t d2 = dec[i-1]*dec[i-1] % n;
439 if ( bin[i] > 0 ) d2 *= a;
440 dec[i] = d2 % n;
441 } // for i
442
443 return dec[r-1];
444 }
445 //--------------------------------------------------------------------------
446 // Check setup readiness for encryption
447 //--------------------------------------------------------------------------
449
450 if ( !m_isOkForEnc ) {
451 if ( m_n > 0 && m_e > 1 && m_e < m_n ) {
452 m_isOkForEnc = true;
453 } else {
454 ATH_MSG_ERROR("Setup not OK for encryption: public key set?");
455 }
456 } // if ! m_isOkForEnc
457
458 return m_isOkForEnc;
459 }
460
461 //--------------------------------------------------------------------------
462 // Check setup readiness for decryption
463 //--------------------------------------------------------------------------
465
466 if ( !m_isOkForDec ) {
467 if ( m_n > 0 && m_d > 1 && m_d < m_n ) {
468 m_isOkForDec = true;
469 } else {
470 ATH_MSG_ERROR("Setup not OK for decryption: private key set?");
471 }
472 } // if ! m_isOkForDec
473
474 return m_isOkForDec;
475 }
476
477 //--------------------------------------------------------------------------
478} // namespace xAOD
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
@ Data
Definition BaseObject.h:11
static Double_t a
Provide simple asymmetric encryption for blinding of float values.
#define x
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
constexpr int pow(int x)
Definition conifer.h:27
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
setRawEt setRawPhi int