Iray SDK API nvidia_logo_transpbg.gif Up
ilibrary_authentication.h
Go to the documentation of this file.
1/***************************************************************************************************
2 * Copyright 2024 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
116 virtual bool is_trial_license() const = 0;
117
125 virtual Uint64 get_trial_seconds_left() const = 0;
126
131 virtual const IString* get_host_id() const = 0;
132
136 virtual const IString* get_last_error_message() const = 0;
137};
138 // end group mi_neuray_configuration
140
141namespace detail {
142
143// Generates a nonce.
144//
145// \param[out] buffer The buffer for the nonce. Needs to be able to hold 32 bytes.
146static void generate_nonce( char* buffer);
147
148// Generates the response for a challenge, salt, and secret key.
149//
150// \param salt The salt (32 bytes).
151// \param challenge The challenge (32 bytes).
152// \param secret_key The secret key used to calculate the response.
153// \param secret_key_length The size of the secret key.
154// \param[out] response The buffer for the response. Needs to be able to hold 32 bytes.
155static void calculate_response(
156 const char* salt, const char* challenge,
157 const char* secret_key, Size secret_key_length, char* response);
158
159// Computes a SHA256 hash value.
160//
161// \param input The input for which to compute the SHA256 hash value.
162// \param input_length The size of the input.
163// \param[out] buffer The buffer for the SHA256 hash value. Needs to be able to hold 32 bytes.
164static void sha256( const char* input, unsigned int input_length, char* buffer);
165
166} // namespace detail
167
169 const INeuray* library,
170 const char* vendor_key, Size vendor_key_length,
171 const char* secret_key, Size secret_key_length,
172 Sint32 count)
173{
174 if( !library)
175 return -1;
176
179 if( !authenticator.is_valid_interface())
180 return -2;
181
182 char challenge[32];
183 memset( &challenge[0], 0, 32);
184 if( authenticator->get_challenge( challenge, sizeof( challenge)) > sizeof( challenge))
185 return -3;
186
187 char salt[32];
188 detail::generate_nonce( salt);
189
190 char response[32];
191 detail::calculate_response( salt, challenge, secret_key, secret_key_length, response);
192
193 authenticator->submit_challenge_response(
194 response, sizeof( response), vendor_key, vendor_key_length, salt, sizeof( salt), count);
195 return 0;
196}
197
198namespace detail {
199
200void calculate_response(
201 const char* salt, const char* challenge,
202 const char* secret_key, Size secret_key_length, char* response)
203{
204 if( secret_key_length > 1024u * 10u)
205 return;
206 // salt = 32 bytes, challenge = 32 bytes
207 Size total_len = 32u + 32u + secret_key_length;
208 char* buffer = new char[total_len];
209 memcpy( buffer, salt, 32);
210 memcpy( buffer + 32, challenge, 32);
211 memcpy( buffer + 64, secret_key, secret_key_length);
212 sha256( buffer, static_cast<Uint32>( total_len), response);
213 delete[] buffer;
214}
215
216void generate_nonce( char* buffer)
217{
218 if( buffer == 0)
219 return;
220 Uint64 number = 0;
221#ifdef MI_PLATFORM_WINDOWS
222 srand( GetTickCount());
223 LARGE_INTEGER tmp;
224 QueryPerformanceCounter( &tmp);
225 number += tmp.QuadPart + GetCurrentProcessId() + GetTickCount();
226#else
227 // Note: icc 13.1 report warning here as an implicit conversion,
228 // but this is an explicit conversion.
229 srand( static_cast<unsigned>( time( 0)));
230 struct timeval tv;
231 gettimeofday( &tv, 0);
232 number += static_cast<Uint64>( tv.tv_sec + tv.tv_usec);
233#endif
234 char buf[sizeof( Uint32) + 3*sizeof( Uint64)] = {0};
235 int r = rand();
236 memcpy( buf, &r, sizeof( Uint32));
237 memcpy( buf + sizeof( Uint32), &number, sizeof( Uint64));
238 memcpy( buf + sizeof( Uint32) + sizeof( Uint64), &number, sizeof( Uint64));
239 number += static_cast<Uint64>( rand());
240 memcpy( buf + sizeof( Uint32) + 2*sizeof( Uint64), &number, sizeof( Uint64));
241 sha256( buf, static_cast<Uint32>( sizeof( buf)), buffer);
242}
243
244// Table of round constants.
245// First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
246static const Uint32 sha256_constants[] = {
247 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
248 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
249 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
250 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
251 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
252 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
253 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
254 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
255};
256
257// Reverses the byte order of the bytes of \p x
258static Uint32 flip32( Uint32 x)
259{
260 return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) |
261 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
262}
263
264// Rotates the bits of \p x to the right by \p y bits
265static Uint32 rightrotate( Uint32 x, Uint32 y)
266{
267 return (( x >> y) | (x << (32-y)));
268}
269
270void sha256( const char* input, unsigned int input_length, char* buffer)
271{
272 if( (input_length <= 0) || (input == 0) || (buffer == 0))
273 return;
274
275 // First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
276 Uint32 state[] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
277 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
278
279 // k is the number of '0' bits >= 0 such that the resulting message length is 448 (mod 512)
280 unsigned int r = (input_length * 8 + 1) % 512;
281 unsigned int k = r > 448 ? 960 - r : 448 - r;
282
283 unsigned int pos = 0;
284 for( unsigned int chunk = 0; k != 0; ++chunk) {
285
286 Uint32 W[64] = {0};
287 Uint8* ptr = reinterpret_cast<Uint8*>( W);
288 unsigned int to_copy = input_length - pos;
289 to_copy = to_copy > 64 ? 64 : to_copy;
290 if( to_copy > 0) {
291 memcpy( ptr, input + pos, to_copy);
292 pos += to_copy;
293 }
294
295 // If we are at the end of input message
296 if( pos == input_length) {
297 // If we still have not padded and have space to add a 1, add it
298 if( pos/64 == chunk)
299 ptr[pos%64] |= static_cast<Uint8>( 0x80);
300 // If we can pad and still have space to add the length, add it
301 if( (pos*8 + 1 + k) - (chunk*512) <= 448) {
302 Uint64 value = input_length * 8;
303 ptr = reinterpret_cast<Uint8*>(&W[14]);
304 // Note: icc 13.1 report warning for the following
305 // code as an implicit conversion, but this is an
306 // explicit conversion.
307 ptr[0] = static_cast<Uint8>((value >> 56) & 0xff);
308 ptr[1] = static_cast<Uint8>((value >> 48) & 0xff);
309 ptr[2] = static_cast<Uint8>((value >> 40) & 0xff);
310 ptr[3] = static_cast<Uint8>((value >> 32) & 0xff);
311 ptr[4] = static_cast<Uint8>((value >> 24) & 0xff);
312 ptr[5] = static_cast<Uint8>((value >> 16) & 0xff);
313 ptr[6] = static_cast<Uint8>((value >> 8) & 0xff);
314 ptr[7] = static_cast<Uint8>( value & 0xff);
315 k = 0;
316 }
317 }
318
319 // Flip to big endian
320 for( int i = 0; i < 16; ++i)
321 W[i] = flip32( W[i]);
322
323 // Extend the sixteen 32-bit words into 64 32-bit words
324 for( Uint32 i = 16; i < 64; ++i) {
325 Uint32 s0 = rightrotate( W[i-15], 7) ^ rightrotate( W[i-15], 18) ^ (W[i-15] >> 3);
326 Uint32 s1 = rightrotate( W[i-2], 17) ^ rightrotate( W[i- 2], 19) ^ (W[i-2] >> 10);
327 W[i] = W[i-16] + s0 + W[i-7] + s1;
328 }
329
330 // Initialize hash value for this chunk
331 Uint32 a = state[0];
332 Uint32 b = state[1];
333 Uint32 c = state[2];
334 Uint32 d = state[3];
335 Uint32 e = state[4];
336 Uint32 f = state[5];
337 Uint32 g = state[6];
338 Uint32 h = state[7];
339
340 for( Uint32 j = 0; j < 64; ++j) {
341 Uint32 s0 = rightrotate( a, 2) ^ rightrotate( a, 13) ^ rightrotate( a, 22);
342 Uint32 maj = (a & b) ^ (a & c) ^ (b & c);
343 Uint32 t2 = s0 + maj;
344 Uint32 s1 = rightrotate( e, 6) ^ rightrotate( e, 11) ^ rightrotate( e, 25);
345 Uint32 ch = (e & f) ^ ((~e) & g);
346 Uint32 t1 = h + s1 + ch + sha256_constants[j] + W[j];
347
348 h = g; g = f; f = e; e = d + t1;
349 d = c; c = b; b = a; a = t1 + t2;
350 }
351
352 // Add this chunk's hash value to result so far
353 state[0] += a; state[1] += b; state[2] += c; state[3] += d;
354 state[4] += e; state[5] += f; state[6] += g; state[7] += h;
355 }
356
357 // Flip to little endian
358 for( int i = 0; i < 8; ++i)
359 state[i] = flip32( state[i]);
360
361 memcpy( buffer, reinterpret_cast<char*>( state), 32);
362}
363
364} // namespace detail
365
366} // namespace neuraylib
367
368} // namespace mi
369
370#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.
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:168
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.
This is an object representing the Iray library.
Definition: ineuray.h:44
virtual base::IInterface * get_api_component(const base::Uuid &uuid) const =0
Returns an API component from the Iray SDK 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 Iray SDK API interface.
Mixin class template for deriving new interface declarations.
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH.
Definition: neuraylib.h:179