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