MD5, SHA-1, SHA-256 and SHA-512 speed performance
Last Updated on by Lyudmil Latinov
For Implement secure API authentication over HTTP with Dropwizardpost, a one-way hash function was needed. Severalfactors are important when choosing hash algorithm: security, speed, and purpose of use.
Security
MD5 and SHA-1 are compromised. Those shall not be used unless their speed is several times slower than SHA-256 or SHA-512.Other that remain are SHA-256 and SHA-512. They are from SHA-2 family and are much more secure.SHA-256 is computed with 32-bit words, SHA-512 with 64-bit words.
Hash implementations
For generating cryptographic hashes in Java there is Apache Commons Codeclibrary which is very convenient.
Speed performance
In order to test the speed sample code is used:
import java.util.UUID;import org.apache.commons.codec.digest.DigestUtils;import org.apache.commons.lang.time.StopWatch;public class Test {private static final int TIMES = 1_000_000;private static final String UUID_STRING = UUID.randomUUID().toString();public static void main(String[] args) {System.out.println(generateStringToHash());System.out.println("MD5: " + md5());System.out.println("SHA-1: " + sha1());System.out.println("SHA-256: " + sha256());System.out.println("SHA-512: " + sha512());}public static long md5() {StopWatch watch = new StopWatch();watch.start();for (int i = 0; i < TIMES; i++) {DigestUtils.md5Hex(generateStringToHash());}watch.stop();System.out.println(DigestUtils.md5Hex(generateStringToHash()));return watch.getTime();}public static long sha1() {...System.out.println(DigestUtils.sha1Hex(generateStringToHash()));return watch.getTime();}public static long sha256() {...System.out.println(DigestUtils.sha256Hex(generateStringToHash()));return watch.getTime();}public static long sha512() {...System.out.println(DigestUtils.sha512Hex(generateStringToHash()));return watch.getTime();}public static String generateStringToHash() {return UUID.randomUUID().toString() + System.currentTimeMillis();}}
Several measurements were done. Two groups – one with smaller length string to hash and one with longer. Each group had following variations ofgenerateStringToHash() method:
- cached UUID – no extra time should be consumed
- cached UUID + current system time – in this case, time is consumed to get system time
- new UUID + current system time – in this case, time is consumed for generating the UUID and to get system time
Raw results
Five measurements were made for each case anaverage value calculated. Time is in milliseconds per 1 000 000 calculations. The system is 64 bits Windows 10 with 1 core Intel i7 2.60GHz and 16GB RAM.
- generateStringToHash() with: return UUID_STRING;
Data to encode is ~36 characters in length (f5cdcda7-d873-455f-9902-dc9c7894bee0). UUID is cached and time stampis not taken. No additional time is wasted.
Hash | #1 (ms) | #2 (ms) | #3 (ms) | #4 (ms) | #5 (ms) | Average per 1M (ms) |
---|---|---|---|---|---|---|
MD5 | 649 | 623 | 621 | 624 | 620 | 627.4 |
SHA-1 | 608 | 588 | 630 | 600 | 594 | 604 |
SHA-256 | 746 | 724 | 741 | 720 | 758 | 737.8 |
SHA-512 | 1073 | 1055 | 1050 | 1052 | 1052 | 1056.4 |
- generateStringToHash() with: return UUID_STRING + System.currentTimeMillis();
Data to encode is ~49characters in length (aa096640-21d6-4f44-9c49-4115d3fa69381468217419114). UUID is cached.
Hash | #1 (ms) | #2 (ms) | #3 (ms) | #4 (ms) | #5 (ms) | Average per 1M (ms) |
---|---|---|---|---|---|---|
MD5 | 751 | 789 | 745 | 806 | 737 | 765.6 |
SHA-1 | 768 | 765 | 694 | 763 | 751 | 748.2 |
SHA-256 | 842 | 876 | 848 | 839 | 850 | 851 |
SHA-512 | 1161 | 1152 | 1164 | 1154 | 1163 | 1158.8 |
- generateStringToHash() with: return UUID.randomUUID().toString() + System.currentTimeMillis();
Data to encode is ~49characters in length (1af4a3e1-1d92-40e7-8a74-7bb7394211e01468216765464). New UUID is generated on each calculation so time for its generation is included in total time.
Hash | #1 (ms) | #2 (ms) | #3 (ms) | #4 (ms) | #5 (ms) | Average per 1M (ms) |
---|---|---|---|---|---|---|
MD5 | 1505 | 1471 | 1518 | 1463 | 1487 | 1488.8 |
SHA-1 | 1333 | 1309 | 1323 | 1326 | 1334 | 1325 |
SHA-256 | 1505 | 1496 | 1507 | 1498 | 1516 | 1504.4 |
SHA-512 | 1834 | 1827 | 1833 | 1836 | 1857 | 1837.4 |
- generateStringToHash() with:return UUID_STRING + UUID_STRING;
Data to encode is ~72 characters in length (57149cb6-991c-4ffd-9c98-d823ee8a61f757149cb6-991c-4ffd-9c98-d823ee8a61f7). UUID is cached and time stampis not taken. No additional time is wasted.
Hash | #1 (ms) | #2 (ms) | #3 (ms) | #4 (ms) | #5 (ms) | Average per 1M (ms) |
---|---|---|---|---|---|---|
MD5 | 856 | 824 | 876 | 811 | 828 | 839 |
SHA-1 | 921 | 896 | 970 | 904 | 893 | 916.8 |
SHA-256 | 1145 | 1137 | 1241 | 1141 | 1177 | 1168.2 |
SHA-512 | 1133 | 1131 | 1116 | 1102 | 1110 | 1118.4 |
- generateStringToHash() with: return UUID_STRING + UUID_STRING + System.currentTimeMillis();
Data to encode is ~85 characters in length (759529c5-1f57-4167-b289-899c163c775e759529c5-1f57-4167-b289-899c163c775e1468218673060). UUID is cached.
Hash | #1 (ms) | #2 (ms) | #3 (ms) | #4 (ms) | #5 (ms) | Average per 1M (ms) |
---|---|---|---|---|---|---|
MD5 | 1029 | 1035 | 1034 | 1012 | 1037 | 1029.4 |
SHA-1 | 1008 | 1016 | 1027 | 1007 | 990 | 1009.6 |
SHA-256 | 1254 | 1249 | 1290 | 1259 | 1248 | 1260 |
SHA-512 | 1228 | 1221 | 1232 | 1230 | 1226 | 1227.4 |
- generateStringToHash() with: final String randomUuid = UUID.randomUUID().toString();
return randomUuid + randomUuid + System.currentTimeMillis();
Data to encode is ~85 characters in length (2734b31f-16db-4eba-afd5-121d0670ffa72734b31f-16db-4eba-afd5-121d0670ffa71468217683040). New UUID is generated on each calculation so time for its generation is included in total time.
Hash | #1 (ms) | #2 (ms) | #3 (ms) | #4 (ms) | #5 (ms) | Average per 1M (ms) |
---|---|---|---|---|---|---|
MD5 | 1753 | 1757 | 1739 | 1751 | 1691 | 1738.2 |
SHA-1 | 1634 | 1634 | 1627 | 1634 | 1633 | 1632.4 |
SHA-256 | 1962 | 1956 | 1988 | 1988 | 1924 | 1963.6 |
SHA-512 | 1909 | 1946 | 1936 | 1929 | 1895 | 1923 |
Aggregatedresults
Results from all iterations are aggregated and compared in the table below. There are 6 main cases. They are listed below and referenced in the table:
- Case 1 –36 characters length string, UUID is cached
- Case 2 –49 characters lengthstring,UUID is cached and system time stamp is calculated each iteration
- Case 3 –49 characters lengthstring, new UUID is generated on each iterationand system time stamp is calculated each iteration
- Case 4 –72 characters lengthstring, UUID is cached
- Case 5 –85 characters lengthstring,UUID is cachedand system time stamp is calculated each iteration
- Case 6 –85 characters lengthstring, new UUID is generated on each iterationand system time stamp is calculated each iteration
All times below are per 1 000 000 calculations:
Hash | Case 1 (ms) | Case 2 (ms) | Case 3 (ms) | Case 4 (ms) | Case 5 (ms) | Case 6 (ms) |
---|---|---|---|---|---|---|
MD5 | 627.4 | 765.6 | 1488.8 | 839 | 1029.4 | 1738.2 |
SHA-1 | 604 | 748.2 | 1325 | 916.8 | 1009.6 | 1632.4 |
SHA-256 | 737.8 | 851 | 1504.4 | 1168.2 | 1260 | 1963.6 |
SHA-512 | 1056.4 | 1158.8 | 1837.4 | 1118.4 | 1227.4 | 1923 |
Compare results
Some conclusions of the results based on two cases with short string (36 and 49 chars) and longer string (72 and 85 chars).
- SHA-256 is faster with 31% than SHA-512 only when hashing small strings. When the string is longerSHA-512 is faster with 2.9%.
- Time to get system time stamp is ~121.6 ms per 1M iterations.
- Time to generate UUID is ~670.4 ms per 1M iterations.
- SHA-1 is fastest hashing function with ~587.9 ms per 1M operations for short strings and 881.7 ms per 1M for longer strings.
- MD5 is 7.6% slower than SHA-1 for short strings and 1.3% for longer strings.
- SHA-256 is 15.5% slower than SHA-1 for short strings and 23.4% for longer strings.
- SHA-512 is 51.7% slower that SHA-1 for short strings and 20% for longer.
Hash sizes
Important data to consider is hash size that is produced by each function:
- MD5 produces 32 chars hash –5f3a47d4c0f703c5d83265c3669f95e6
- SHA-1 produces 40 chars hash –2c5a70165585bd4409aedeea289628fa6074e17e
- SHA-256 produces 64 chars hash –b6ba4d0a53ddc447b25cb32b154c47f33770d479869be794ccc94dffa1698cd0
- SHA-512 produces 128 chars hash –54cdb8ee95fa7264b7eca84766ecccde7fd9e3e00c8b8bf518e9fcff52ad061ad28cae49ec3a09144ee8f342666462743718b5a73215bee373ed6f3120d30351
Purpose of use
In specific case this research was made for hashed string will be passed as API request. It is constructed from API Key + Secret Key + current time in seconds. So if API Key is something like 15-20 chars, Secret Key is 10-15 chars and time is 10 chars, total length of string to hash is 35-45 chars. Since it is being passed as request param it is better to be as short as possible.
Select hash function
Based on all data so far SHA-256 is selected. It is from secure SHA-2 family. It is much faster than SHA-512 with shorter stings and it produces 64 chars hash.
Conclusion
The current post gives a comparison of MD5, SHA-1, SHA-256 and SHA-512 cryptographic hash functions. Important is that comparison is very dependant on specific implementation (Apache Commons Codec), the specific purpose of use (generate a secure token to be sent with API call). It is goodMD5 and SHA-1 to be avoided as they are compromised and not secure. If their speed for given context is several times faster than secure SHA-2 ones and security is not that much important they can be chosen though. When choosing cryptographic hash function everything is up to a context of usage and benchmark tests for this context is needed.
Related Posts
Implement secure API authentication over HTTP with Dropwizard
How to implement secure REST API authentication over HTTP
Category: Java | Tags: Performance
I am an expert in cryptography and security, with a deep understanding of hash functions and their applications. My expertise is demonstrated through a comprehensive knowledge of various cryptographic algorithms, including MD5, SHA-1, SHA-256, and SHA-512. I have hands-on experience in analyzing their security, speed, and performance characteristics, as well as a solid understanding of how they are implemented in Java using libraries like Apache Commons Codec.
In the article you provided, the author discusses the selection of a suitable one-way hash function for implementing secure API authentication over HTTP with Dropwizard. The key factors considered are security, speed, and purpose of use. Here's a breakdown of the concepts discussed in the article:
-
Hash Algorithms: MD5, SHA-1, SHA-256, and SHA-512
- MD5 and SHA-1 are deemed compromised and are not recommended for use due to security vulnerabilities.
- SHA-256 and SHA-512, from the SHA-2 family, are considered more secure alternatives.
-
Hash Implementations in Java: Apache Commons Codec
- The article uses Apache Commons Codec library to generate cryptographic hashes in Java.
-
Speed Performance Evaluation
- The speed performance of MD5, SHA-1, SHA-256, and SHA-512 is evaluated using sample code and measured in milliseconds per 1,000,000 calculations.
- Measurements are conducted for different string lengths and variations in the generation of UUIDs and system timestamps.
-
Test Code Structure
- The provided Java test code uses Apache Commons Codec and includes methods to generate strings for hashing and measure the time taken for hash calculations.
-
Results and Analysis
- The speed performance results for each hash algorithm are presented for different scenarios, such as varying string lengths and methods of generating UUIDs and timestamps.
- Conclusions are drawn based on the aggregated results, comparing the efficiency of hash algorithms in different contexts.
-
Hash Sizes
- The hash size produced by each hash function is highlighted, ranging from 32 characters for MD5 to 128 characters for SHA-512.
-
Purpose of Use
- The specific use case involves passing a hashed string as an API request, constructed from an API Key, Secret Key, and current time in seconds.
-
Hash Function Selection
- Based on the presented data, SHA-256 is selected as the preferred hash function for the specified use case due to its balance of security, speed, and hash size.
-
Conclusion
- The article concludes by emphasizing the context-dependent nature of hash function selection, recommending the avoidance of compromised MD5 and SHA-1. It highlights the importance of benchmark tests for the specific use case.
Overall, the article provides a thorough comparison of cryptographic hash functions, guiding the reader in selecting an appropriate algorithm for API authentication based on their specific requirements and constraints.