NVIDIA Iray API
 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, 2014 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 namespace neuraylib {
28 
33 class ILibrary_authenticator : public
41  mi::base::Interface_declare<0x5a7d010a,0x2a65,0x43da,0x92,0xf2,0xcd,0xd9,0xc8,0x4b,0x10,0xd2>
42 {
43 public:
64  inline static Sint32 authenticate(
65  const INeuray* library,
66  const char* vendor_key, Sint32 vendor_key_length,
67  const char* secret_key, Sint32 secret_key_length);
68 
69  // Returns a challenge from the library.
70  //
71  // Asks the library for a challenge. The authentication process combines the challenge with the
72  // secret key and the vendor key to generate the correct response.
73  //
74  // \note This method is internal and should not be called directly. Use the convenience method
75  // #authenticate() instead.
76  //
77  // \param buffer The library will store the challenge here.
78  // \param buffer_length The actual size of the buffer. If the buffer is not big enough
79  // generating the challenge generation will fail. Currently, the buffer
80  // should be able to hold at least 32 bytes.
81  // \return The necessary size of the needed buffer. The application needs to
82  // check this value to determine whether its supplied buffer was big
83  // enough, otherwise the challenge is not valid.
84  virtual Sint32 get_challenge(char* buffer, Sint32 buffer_length) = 0;
85 
86  // Submits the calculated response to a challenge.
87  //
88  // In addition, the application has to provide a vendor key and a random salt. This is used to
89  // make attacks more difficult.
90  //
91  // \note This method is internal and should not be called directly. Use the convenience method
92  // #authenticate() instead.
93  //
94  // \param response The calculated response.
95  // \param response_length The size of the response.
96  // \param vendor_key The vendor key assigned to the application writer.
97  // \param vendor_key_length The size of the vendor key.
98  // \param salt A random salt. Should be a random array of bytes.
99  // \param salt_length The size of the salt.
100  virtual void submit_challenge_response(
101  const char* response, Sint32 response_length,
102  const char* vendor_key, Sint32 vendor_key_length,
103  const char* salt, Sint32 salt_length) = 0;
104 };
105 
106 namespace detail
107 {
108 // Generates a nounce.
109 //
110 // \param[out] out_buffer The buffer for the nounce. Needs to be able to hold 32 bytes.
111 static void generate_nounce( char* out_buffer);
112 
113 // Generates the response for a challenge, salt, and secret key.
114 //
115 // \param salt The salt (32 bytes).
116 // \param challenge The challenge (32 bytes).
117 // \param secret_key The secret key used to calculate the response.
118 // \param secret_key_length The size of the secret key.
119 // \param[out] out_response The buffer for the response. Needs to be able to hold 32 bytes.
120 static void calculate_response(
121  const char* salt, const char* challenge,
122  const char* secret_key, Sint32 secret_key_length, char* out_response);
123 
124 // Computes a SHA256 hash value.
125 //
126 // \param input The input for which to compute the SHA256 hash value.
127 // \param input_length The size of the input.
128 // \param[out] out_buffer The buffer for the SHA256 hash value. Needs to be able to hold 32 bytes.
129 static void sha256( const char* input, int input_length, char* out_buffer);
130 }
131 
133  const INeuray* library,
134  const char* vendor_key, Sint32 vendor_key_length,
135  const char* secret_key, Sint32 secret_key_length)
136 {
137  if( !library)
138  return -1;
139 
142  if( !authenticator.is_valid_interface())
143  return -2;
144 
145  char challenge[32];
146  memset( &challenge[0], 0, 32);
147  if( authenticator->get_challenge( challenge, static_cast<Sint32>( sizeof( challenge)))
148  > static_cast<Sint32>( sizeof( challenge)))
149  return -3;
150 
151  char salt[32];
152  detail::generate_nounce( salt);
153 
154  char response[32];
155  detail::calculate_response( salt, challenge, secret_key, secret_key_length, response);
156 
157  authenticator->submit_challenge_response(
158  response, static_cast<Sint32>( sizeof( response)), vendor_key, vendor_key_length,
159  salt, static_cast<Sint32>( sizeof( salt)));
160  return 0;
161 }
162 
163 namespace detail
164 {
165 
166 void calculate_response(
167  const char* salt, const char* challenge,
168  const char* secret_key, Sint32 secret_key_length, char* out_response)
169 {
170  if( (secret_key_length < 0) || (secret_key_length > 1024*10))
171  return;
172  // salt = 32 bytes, challenge = 32 bytes
173  int total_len = 32 + 32 + secret_key_length;
174  char* buffer = new char[total_len];
175  memcpy( buffer, salt, 32);
176  memcpy( buffer + 32, challenge, 32);
177  memcpy( buffer + 64, secret_key, secret_key_length);
178  sha256( buffer, total_len, out_response);
179  delete[] buffer;
180 }
181 
182 void generate_nounce( char* out_buffer)
183 {
184  if( out_buffer == 0)
185  return;
186  Uint64 number = 0;
187 #ifdef MI_PLATFORM_WINDOWS
188  srand( GetTickCount());
189  LARGE_INTEGER tmp;
190  QueryPerformanceCounter( &tmp);
191  number += tmp.QuadPart + GetCurrentProcessId() + GetTickCount();
192 #else
193  srand( static_cast<unsigned>( time( 0)));
194  struct timeval tv;
195  gettimeofday( &tv, 0);
196  number += tv.tv_sec + tv.tv_usec;
197 #endif
198  char buf[sizeof( Uint32) + 3*sizeof( Uint64)] = {0};
199  int r = rand();
200  memcpy( buf, &r, sizeof( Uint32));
201  memcpy( buf + sizeof( Uint32), &number, sizeof( Uint64));
202  memcpy( buf + sizeof( Uint32) + sizeof( Uint64), &number, sizeof( Uint64));
203  number += rand();
204  memcpy( buf + sizeof( Uint32) + 2*sizeof( Uint64), &number, sizeof( Uint64));
205  sha256( const_cast<const char*>( buf), static_cast<Sint32>( sizeof( buf)), out_buffer);
206 }
207 
208 // Table of round constants.
209 // First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
210 static const Uint32 sha256_constants[] = {
211  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
212  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
213  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
214  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
215  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
216  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
217  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
218  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
219 };
220 
221 // Reverses the byte order of the bytes of \p x
222 static Uint32 flip32( Uint32 x)
223 {
224  return ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) |
225  (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24));
226 }
227 
228 // Rotates the bits of \p x to the right by \p y bits
229 static Uint32 rightrotate( Uint32 x, Uint32 y)
230 {
231  return (( x >> y) | (x << (32-y)));
232 }
233 
234 void sha256( const char* input, int input_length, char* out_buffer)
235 {
236  if( (input_length <= 0) || (input == 0) || (out_buffer == 0))
237  return;
238 
239  // First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
240  Uint32 state[] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
241  0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
242 
243  // k is the number of '0' bits >= 0 such that the resulting message length is 448 (mod 512)
244  int k = 448 - (input_length * 8 + 1) % 512;
245  if( k < 0)
246  k += 512;
247 
248  int pos = 0;
249  for( int chunk = 0; k != 0; ++chunk) {
250 
251  Uint32 W[64] = {0};
252  Uint8* ptr = reinterpret_cast<Uint8*>( W);
253  int to_copy = input_length - pos;
254  to_copy = to_copy > 64 ? 64 : to_copy;
255  if( to_copy > 0) {
256  memcpy( ptr, input + pos, to_copy);
257  pos += to_copy;
258  }
259 
260  // If we are at the end of input message
261  if( pos == input_length) {
262  // If we still have not padded and have space to add a 1, add it
263  if( (k > 0) && (pos % 64 < 64) && (pos/64 == chunk))
264  ptr[pos%64] |= static_cast<Uint8>( 0x80);
265  // If we can pad and still have space to add the length, add it
266  if( (pos*8 + 1 + k) - (chunk*512) <= 448) {
267  Uint64 value = input_length * 8;
268  ptr = reinterpret_cast<Uint8*>(&W[14]);
269  ptr[0] = static_cast<Uint8>((value >> 56) & 0xff);
270  ptr[1] = static_cast<Uint8>((value >> 48) & 0xff);
271  ptr[2] = static_cast<Uint8>((value >> 40) & 0xff);
272  ptr[3] = static_cast<Uint8>((value >> 32) & 0xff);
273  ptr[4] = static_cast<Uint8>((value >> 24) & 0xff);
274  ptr[5] = static_cast<Uint8>((value >> 16) & 0xff);
275  ptr[6] = static_cast<Uint8>((value >> 8) & 0xff);
276  ptr[7] = static_cast<Uint8>( value & 0xff);
277  k = 0;
278  }
279  }
280 
281  // Flip to big endian
282  for( int i = 0; i < 16; ++i)
283  W[i] = flip32( W[i]);
284 
285  // Extend the sixteen 32-bit words into 64 32-bit words
286  for( Uint32 i = 16; i < 64; ++i) {
287  Uint32 s0 = rightrotate( W[i-15], 7) ^ rightrotate( W[i-15], 18) ^ (W[i-15] >> 3);
288  Uint32 s1 = rightrotate( W[i-2], 17) ^ rightrotate( W[i- 2], 19) ^ (W[i-2] >> 10);
289  W[i] = W[i-16] + s0 + W[i-7] + s1;
290  }
291 
292  // Initialize hash value for this chunk
293  Uint32 a = state[0];
294  Uint32 b = state[1];
295  Uint32 c = state[2];
296  Uint32 d = state[3];
297  Uint32 e = state[4];
298  Uint32 f = state[5];
299  Uint32 g = state[6];
300  Uint32 h = state[7];
301 
302  for( Uint32 j = 0; j < 64; ++j) {
303  Uint32 s0 = rightrotate( a, 2) ^ rightrotate( a, 13) ^ rightrotate( a, 22);
304  Uint32 maj = (a & b) ^ (a & c) ^ (b & c);
305  Uint32 t2 = s0 + maj;
306  Uint32 s1 = rightrotate( e, 6) ^ rightrotate( e, 11) ^ rightrotate( e, 25);
307  Uint32 ch = (e & f) ^ ((~e) & g);
308  Uint32 t1 = h + s1 + ch + sha256_constants[j] + W[j];
309 
310  h = g; g = f; f = e; e = d + t1;
311  d = c; c = b; b = a; a = t1 + t2;
312  }
313 
314  // Add this chunk's hash value to result so far
315  state[0] += a; state[1] += b; state[2] += c; state[3] += d;
316  state[4] += e; state[5] += f; state[6] += g; state[7] += h;
317  }
318 
319  // Flip to little endian
320  for( int i = 0; i < 8; ++i)
321  state[i] = flip32( state[i]);
322 
323  memcpy( out_buffer, reinterpret_cast<char*>( state), 32);
324 }
325 
326 } // namespace detail
327  // end group mi_neuray_configuration
329 
330 } // namespace neuraylib
331 
332 } // namespace mi
333 
334 #endif // MI_NEURAYLIB_ILIBRARY_AUTHENTICATION_H