DiCE API nvidia_logo_transpbg.gif Up
ilibrary_authentication.h
Go to the documentation of this file.
1/***************************************************************************************************
2 * Copyright 2023 NVIDIA Corporation. All rights reserved.
3 **************************************************************************************************/
6
7#ifndef MI_NEURAYLIB_ILIBRARY_AUTHENTICATION_H
8#define MI_NEURAYLIB_ILIBRARY_AUTHENTICATION_H
9
10#include <mi/base/handle.h>
13
14#ifdef MI_PLATFORM_WINDOWS
15#include <mi/base/miwindows.h>
16#else
17#include <sys/time.h>
18#include <cstdlib>
19#include <ctime>
20#endif
21
22#include <cstring>
23
24namespace mi {
25
26class IString;
27
28namespace neuraylib {
29
42 mi::base::Interface_declare<0x5a7d010a,0x2a65,0x43da,0x92,0xf2,0xcd,0xd9,0xc8,0x4b,0x10,0xd2>
43{
44public:
66 inline static Sint32 authenticate(
67 const INeuray* library,
68 const char* vendor_key, Size vendor_key_length,
69 const char* secret_key, Size secret_key_length,
70 Sint32 count=1);
71
72 // Returns a challenge from the library.
73 //
74 // Asks the library for a challenge. The authentication process combines the challenge with the
75 // secret key and the vendor key to generate the correct response.
76 //
77 // \note This method is internal and should not be called directly. Use the convenience method
78 // #authenticate() instead.
79 //
80 // \param buffer The library will store the challenge here.
81 // \param buffer_length The actual size of the buffer. If the buffer is not big enough
82 // generating the challenge generation will fail. Currently, the buffer
83 // should be able to hold at least 32 bytes.
84 // \return The necessary size of the needed buffer. The application needs to
85 // check this value to determine whether its supplied buffer was big
86 // enough, otherwise the challenge is not valid.
87 virtual Size get_challenge( char* buffer, Size buffer_length) = 0;
88
89 // Submits the calculated response to a challenge.
90 //
91 // In addition, the application has to provide a vendor key and a random salt. This is used to
92 // make attacks more difficult.
93 //
94 // \note This method is internal and should not be called directly. Use the convenience method
95 // #authenticate() instead.
96 //
97 // \param response The calculated response.
98 // \param response_length The size of the response.
99 // \param vendor_key The vendor key assigned to the application writer.
100 // \param vendor_key_length The size of the vendor key.
101 // \param salt A random salt. Should be a random array of bytes.
102 // \param salt_length The size of the salt.
103 // \param count The number of licenses to retrieve.
104 virtual void submit_challenge_response(
105 const char* response, Size response_length,
106 const char* vendor_key, Size vendor_key_length,
107 const char* salt, Size salt_length,
108 Sint32 count) = 0;
109
119 virtual bool is_trial_license() const = 0;
120
131 virtual Uint64 get_trial_seconds_left() const = 0;
132
137 virtual const IString* get_host_id() const = 0;
138
146 virtual const IString* get_last_error_message() const = 0;
147
159 virtual bool set_flexnet_default_license_path( const char* path) = 0;
160
165 virtual void set_flexnet_trial_license_data( const Uint8* data, Size size) = 0;
166
175 virtual bool is_flexnet_license_available() const = 0;
176};
177 // end group mi_neuray_configuration
179
180namespace detail {
181
182// Generates a nonce.
183//
184// \param[out] buffer The buffer for the nonce. Needs to be able to hold 32 bytes.
185static void generate_nonce( char* buffer);
186
187// Generates the response for a challenge, salt, and secret key.
188//
189// \param salt The salt (32 bytes).
190// \param challenge The challenge (32 bytes).
191// \param secret_key The secret key used to calculate the response.
192// \param secret_key_length The size of the secret key.
193// \param[out] response The buffer for the response. Needs to be able to hold 32 bytes.
194static void calculate_response(
195 const char* salt, const char* challenge,
196 const char* secret_key, Size secret_key_length, char* response);
197
198// Computes a SHA256 hash value.
199//
200// \param input The input for which to compute the SHA256 hash value.
201// \param input_length The size of the input.
202// \param[out] buffer The buffer for the SHA256 hash value. Needs to be able to hold 32 bytes.
203static void sha256( const char* input, unsigned int input_length, char* buffer);
204
205} // namespace detail
206
208 const INeuray* library,
209 const char* vendor_key, Size vendor_key_length,
210 const char* secret_key, Size secret_key_length,
211 Sint32 count)
212{
213 if( !library)
214 return -1;
215
218 if( !authenticator.is_valid_interface())
219 return -2;
220
221 char challenge[32];
222 memset( &challenge[0], 0, 32);
223 if( authenticator->get_challenge( challenge, sizeof( challenge)) > sizeof( challenge))
224 return -3;
225
226 char salt[32];
227 detail::generate_nonce( salt);
228
229 char response[32];
230 detail::calculate_response( salt, challenge, secret_key, secret_key_length, response);
231
232 authenticator->submit_challenge_response(
233 response, sizeof( response), vendor_key, vendor_key_length, salt, sizeof( salt), count);
234 return 0;
235}
236
237namespace detail {
238
239void calculate_response(
240 const char* salt, const char* challenge,
241 const char* secret_key, Size secret_key_length, char* response)
242{
243 if( secret_key_length > 1024u * 10u)
244 return;
245 // salt = 32 bytes, challenge = 32 bytes
246 Size total_len = 32u + 32u + secret_key_length;
247 char* buffer = new char[total_len];
248 memcpy( buffer, salt, 32);
249 memcpy( buffer + 32, challenge, 32);
250 memcpy( buffer + 64, secret_key, secret_key_length);
251 sha256( buffer, static_cast<Uint32>( total_len), response);
252 delete[] buffer;
253}
254
255void generate_nonce( char* buffer)
256{
257 if( buffer == 0)
258 return;
259 Uint64 number = 0;
260#ifdef MI_PLATFORM_WINDOWS
261 srand( GetTickCount());
262 LARGE_INTEGER tmp;
263 QueryPerformanceCounter( &tmp);
264 number += tmp.QuadPart + GetCurrentProcessId() + GetTickCount();
265#else
266 // Note: icc 13.1 report warning here as an implicit conversion,
267 // but this is an explicit conversion.
268 srand( static_cast<unsigned>( time( 0)));
269 struct timeval tv;
270 gettimeofday( &tv, 0);
271 number += static_cast<Uint64>( tv.tv_sec + tv.tv_usec);
272#endif
273 char buf[sizeof( Uint32) + 3*sizeof( Uint64)] = {0};
274 int r = rand();
275 memcpy( buf, &r, sizeof( Uint32));
276 memcpy( buf + sizeof( Uint32), &number, sizeof( Uint64));
277 memcpy( buf + sizeof( Uint32) + sizeof( Uint64), &number, sizeof( Uint64));
278 number += static_cast<Uint64>( rand());
279 memcpy( buf + sizeof( Uint32) + 2*sizeof( Uint64), &number, sizeof( Uint64));
280 sha256( buf, static_cast<Uint32>( sizeof( buf)), buffer);
281}
282
283// Table of round constants.
284// First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
285static const Uint32 sha256_constants[] = {
286 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
287 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
288 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
289 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
290 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
291 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
292 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
293 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
294};
295
296// Reverses the byte order of the bytes of \p x
297static Uint32 flip32( Uint32 x)
298{
299 return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) |
300 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
301}
302
303// Rotates the bits of \p x to the right by \p y bits
304static Uint32 rightrotate( Uint32 x, Uint32 y)
305{
306 return (( x >> y) | (x << (32-y)));
307}
308
309void sha256( const char* input, unsigned int input_length, char* buffer)
310{
311 if( (input_length <= 0) || (input == 0) || (buffer == 0))
312 return;
313
314 // First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
315 Uint32 state[] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
316 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
317
318 // k is the number of '0' bits >= 0 such that the resulting message length is 448 (mod 512)
319 unsigned int r = (input_length * 8 + 1) % 512;
320 unsigned int k = r > 448 ? 960 - r : 448 - r;
321
322 unsigned int pos = 0;
323 for( unsigned int chunk = 0; k != 0; ++chunk) {
324
325 Uint32 W[64] = {0};
326 Uint8* ptr = reinterpret_cast<Uint8*>( W);
327 unsigned int to_copy = input_length - pos;
328 to_copy = to_copy > 64 ? 64 : to_copy;
329 if( to_copy > 0) {
330 memcpy( ptr, input + pos, to_copy);
331 pos += to_copy;
332 }
333
334 // If we are at the end of input message
335 if( pos == input_length) {
336 // If we still have not padded and have space to add a 1, add it
337 if( pos/64 == chunk)
338 ptr[pos%64] |= static_cast<Uint8>( 0x80);
339 // If we can pad and still have space to add the length, add it
340 if( (pos*8 + 1 + k) - (chunk*512) <= 448) {
341 Uint64 value = input_length * 8;
342 ptr = reinterpret_cast<Uint8*>(&W[14]);
343 // Note: icc 13.1 report warning for the following
344 // code as an implicit conversion, but this is an
345 // explicit conversion.
346 ptr[0] = static_cast<Uint8>((value >> 56) & 0xff);
347 ptr[1] = static_cast<Uint8>((value >> 48) & 0xff);
348 ptr[2] = static_cast<Uint8>((value >> 40) & 0xff);
349 ptr[3] = static_cast<Uint8>((value >> 32) & 0xff);
350 ptr[4] = static_cast<Uint8>((value >> 24) & 0xff);
351 ptr[5] = static_cast<Uint8>((value >> 16) & 0xff);
352 ptr[6] = static_cast<Uint8>((value >> 8) & 0xff);
353 ptr[7] = static_cast<Uint8>( value & 0xff);
354 k = 0;
355 }
356 }
357
358 // Flip to big endian
359 for( int i = 0; i < 16; ++i)
360 W[i] = flip32( W[i]);
361
362 // Extend the sixteen 32-bit words into 64 32-bit words
363 for( Uint32 i = 16; i < 64; ++i) {
364 Uint32 s0 = rightrotate( W[i-15], 7) ^ rightrotate( W[i-15], 18) ^ (W[i-15] >> 3);
365 Uint32 s1 = rightrotate( W[i-2], 17) ^ rightrotate( W[i- 2], 19) ^ (W[i-2] >> 10);
366 W[i] = W[i-16] + s0 + W[i-7] + s1;
367 }
368
369 // Initialize hash value for this chunk
370 Uint32 a = state[0];
371 Uint32 b = state[1];
372 Uint32 c = state[2];
373 Uint32 d = state[3];
374 Uint32 e = state[4];
375 Uint32 f = state[5];
376 Uint32 g = state[6];
377 Uint32 h = state[7];
378
379 for( Uint32 j = 0; j < 64; ++j) {
380 Uint32 s0 = rightrotate( a, 2) ^ rightrotate( a, 13) ^ rightrotate( a, 22);
381 Uint32 maj = (a & b) ^ (a & c) ^ (b & c);
382 Uint32 t2 = s0 + maj;
383 Uint32 s1 = rightrotate( e, 6) ^ rightrotate( e, 11) ^ rightrotate( e, 25);
384 Uint32 ch = (e & f) ^ ((~e) & g);
385 Uint32 t1 = h + s1 + ch + sha256_constants[j] + W[j];
386
387 h = g; g = f; f = e; e = d + t1;
388 d = c; c = b; b = a; a = t1 + t2;
389 }
390
391 // Add this chunk's hash value to result so far
392 state[0] += a; state[1] += b; state[2] += c; state[3] += d;
393 state[4] += e; state[5] += f; state[6] += g; state[7] += h;
394 }
395
396 // Flip to little endian
397 for( int i = 0; i < 8; ++i)
398 state[i] = flip32( state[i]);
399
400 memcpy( buffer, reinterpret_cast<char*>( state), 32);
401}
402
403} // namespace detail
404
405} // namespace neuraylib
406
407} // namespace mi
408
409#endif // MI_NEURAYLIB_ILIBRARY_AUTHENTICATION_H
A simple string class.
Definition: istring.h:22
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
Mixin class template for deriving new interface declarations.
Definition: interface_declare.h:43
This interface is used for authenticating the application against the library.
Definition: ilibrary_authentication.h:43
virtual const IString * get_last_error_message() const =0
Returns the last error message related to authentication.
virtual bool set_flexnet_default_license_path(const char *path)=0
Sets the expected FlexNet license file location.
static Sint32 authenticate(const INeuray *library, const char *vendor_key, Size vendor_key_length, const char *secret_key, Size secret_key_length, Sint32 count=1)
Convenience function implementing the full library authentication.
Definition: ilibrary_authentication.h:207
virtual void set_flexnet_trial_license_data(const Uint8 *data, Size size)=0
Sets the content of the FlexNet trial license.
virtual Uint64 get_trial_seconds_left() const =0
Returns the number of seconds left for time-limited licenses.
virtual bool is_trial_license() const =0
Indicates whether the license provided for authentication is a time-limited license.
virtual const IString * get_host_id() const =0
Returns the host ID of the machine the program is running on.
virtual bool is_flexnet_license_available() const =0
Indicates whether a valid FlexNet license for the submitted response is available.
This is an object representing the DiCE library.
Definition: ineuray.h:44
virtual base::IInterface * get_api_component(const base::Uuid &uuid) const =0
Returns an API component from the DiCE API.
bool is_valid_interface() const
Returns true if the interface is valid.
Definition: handle.h:291
unsigned long long Uint64
64-bit unsigned integer.
Definition: types.h:62
unsigned int Uint32
32-bit unsigned integer.
Definition: types.h:49
unsigned char Uint8
8-bit unsigned integer.
Definition: types.h:47
Uint64 Size
Unsigned integral type that is large enough to hold the size of all types.
Definition: types.h:112
signed int Sint32
32-bit signed integer.
Definition: types.h:46
Smart-pointer handle class for interfaces, const and non-const version.
Main DiCE API interface.
Mixin class template for deriving new interface declarations.
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH.
Definition: dice.h:89