1414import org .joda .time .format .DateTimeFormatter ;
1515import org .json .JSONObject ;
1616
17+ import javax .crypto .KeyGenerator ;
1718import javax .crypto .Mac ;
19+ import javax .crypto .SecretKey ;
1820import javax .crypto .spec .SecretKeySpec ;
1921import java .io .File ;
2022import java .io .IOException ;
2628import java .security .InvalidKeyException ;
2729import java .security .NoSuchAlgorithmException ;
2830import java .util .ArrayList ;
31+ import java .util .Base64 ;
2932import java .util .HashMap ;
3033import java .util .Map ;
3134import java .util .Random ;
@@ -303,6 +306,7 @@ private RequestBody getBody(Map<String, String> data, @Nullable Map<String, File
303306 private Map <String , String > toPayload (Map <String , Object > data ) throws LocalOperationException {
304307 Map <String , Object > dataClone = new HashMap <String , Object >(data );
305308 dataClone .put ("auth" , getAuthData ());
309+ dataClone .put ("nonce" , getNonce ("AES" , 256 ));
306310
307311 Map <String , String > payload = new HashMap <String , String >();
308312 payload .put ("params" , jsonifyData (dataClone ));
@@ -350,14 +354,14 @@ private Map<String, String> getAuthData() {
350354 */
351355 private String getSignature (String message ) throws LocalOperationException {
352356 byte [] kSecret = transloadit .secret .getBytes (Charset .forName ("UTF-8" ));
353- byte [] rawHmac = hmacSHA1 (kSecret , message );
357+ byte [] rawHmac = hmacSHA384 (kSecret , message );
354358 byte [] hexBytes = new Hex ().encode (rawHmac );
355-
356- return new String ( hexBytes , Charset . forName ( "UTF-8" )) ;
359+ String signature = "sha384:" + new String ( hexBytes , Charset . forName ( "UTF-8" ));
360+ return signature ;
357361 }
358362
359- private byte [] hmacSHA1 (byte [] key , String data ) throws LocalOperationException {
360- final String algorithm = "HmacSHA1 " ;
363+ private byte [] hmacSHA384 (byte [] key , String data ) throws LocalOperationException {
364+ final String algorithm = "HmacSHA384 " ;
361365 Mac mac ;
362366
363367 try {
@@ -371,6 +375,25 @@ private byte[] hmacSHA1(byte[] key, String data) throws LocalOperationException
371375 return mac .doFinal (data .getBytes (Charset .forName ("UTF-8" )));
372376 }
373377
378+ /**
379+ * Generates a strong cryptographic nonce in order to make the request's signature unique.
380+ * @param cipher Algorithm to derive key with
381+ * @param lengthInBits Length of the generated key in bits
382+ * @return A Key formatted as String
383+ */
384+ protected String getNonce (String cipher , int lengthInBits ) {
385+ KeyGenerator keyGenerator = null ;
386+ try {
387+ keyGenerator = KeyGenerator .getInstance (cipher );
388+ } catch (NoSuchAlgorithmException e ) {
389+ throw new RuntimeException (e );
390+ }
391+ keyGenerator .init (lengthInBits );
392+ SecretKey secKey = keyGenerator .generateKey ();
393+ String encodedKey = Base64 .getEncoder ().encodeToString (secKey .getEncoded ());
394+ return encodedKey ;
395+ }
396+
374397 /**
375398 * Helper method, which performs a retryRateLimit action if a POST request has hit the servers rate limit.
376399 * All parameters of the failed POST request should be provided to this method.
0 commit comments