Path: blob/master/test/jdk/java/security/MessageDigest/ThreadSafetyTest.java
41149 views
/*1* Copyright (c) 2020, Azul Systems, Inc. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 824196026* @summary Confirm that java.security.MessageDigest is thread-safe after clone.27* @run main/othervm ThreadSafetyTest 5 428*/2930import java.security.MessageDigest;31import java.security.NoSuchAlgorithmException;32import java.security.Provider;33import java.security.Security;34import java.util.Arrays;35import java.util.Random;3637// Usage: java ThreadSafetyTest [threadsFactor [duration]]38public class ThreadSafetyTest {3940static volatile boolean runrun = true;41static volatile boolean error = false;4243private static final String[] ALGORITHM_ARRAY = { "MD2", "MD5",44"SHA1", "SHA-224", "SHA-256", "SHA-384",45"SHA-512", "SHA-512/224", "SHA-512/256",46"SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512" };4748public static void main(String[] args) throws Exception {49int threadsFactor = 5;50if (args.length > 0) {51threadsFactor = Integer.parseInt(args[0]);52}53int duration = 4;54if (args.length > 1) {55duration = Integer.parseInt(args[1]);56}57int nProcessors = Runtime.getRuntime().availableProcessors();58int nTasks = nProcessors * threadsFactor;5960System.out.println("Testing with " + nTasks + " threads on " +61nProcessors + " processors for " + duration +62" seconds.");6364// Initialize input data65byte input[] = new byte[1024];66(new Random()).nextBytes(input);6768for (Provider p : Security.getProviders()) {69for (String alg : ALGORITHM_ARRAY) {70try {71MessageDigest md = MessageDigest.getInstance(alg, p);72testThreadSafety(md, input, nTasks, duration, false);7374if (isClonable(md)) {75md.reset();76testThreadSafety(md, input, nTasks, duration, true);77}78} catch (NoSuchAlgorithmException nae) {79// algorithm not supported, just skip80}81}82}83}8485static private void testThreadSafety(final MessageDigest originalMD,86final byte[] input, final int nTasks,87final int duration, final boolean useClone) {88Thread[] tasks = new Thread[nTasks];8990byte[] expectedOut = getHash(originalMD, input, useClone);91originalMD.reset();9293runrun = true;9495for (int i = 0; i < nTasks; i++) {96tasks[i] = new Thread(new Runnable() {97public void run() {98MessageDigest md = getMessageDigest(originalMD, useClone);99while (runrun) {100byte newOut[] = getHash(md, input, useClone);101if (!Arrays.equals(expectedOut, newOut)) {102runrun = false;103error = true;104}105}106}107});108}109for (int i = 0; i < nTasks; i++) {110tasks[i].start();111}112113try {114for (int i = 0; runrun && i < duration; i++) {115Thread.sleep(1000); // 1 second116}117runrun = false;118for (int i = 0; i < nTasks; i++) {119tasks[i].join();120}121} catch (InterruptedException e) {122}123if (error) {124throw new RuntimeException("MessageDigest " + originalMD.getAlgorithm() +125" in the provider " + originalMD.getProvider().getName() +126" is not thread-safe" + (useClone?" after clone.":"." ));127}128}129130static private byte[] getHash(final MessageDigest messageDigest,131final byte[] input, final boolean useClone) {132for (int i = 0; i < 100; i++)133messageDigest.update(input);134return messageDigest.digest();135}136137static private MessageDigest getMessageDigest(final MessageDigest prototype,138final boolean useClone) {139try {140if (useClone) {141return (MessageDigest)prototype.clone();142}143return MessageDigest.getInstance(144prototype.getAlgorithm(), prototype.getProvider());145} catch (final CloneNotSupportedException | NoSuchAlgorithmException e) {146throw new RuntimeException(e);147}148}149150// The impls from libucrypto does not support clone but ones151// from libmd do.152static private boolean isClonable(final MessageDigest messageDigest) {153try {154messageDigest.clone();155return true;156} catch (final CloneNotSupportedException e) {157return false;158}159}160161}162163164