/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.core.util;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Test;
import org.olat.core.util.Encoder.Algorithm;
/**
*
* Initial date: 23.08.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class EncoderTest {
@Test
public void testCompatibility() {
//the openolat password as saved on our database
String openolat = "c14c4d01c090a065eaa619ca92f8cbc0";
String hashedOpenolat_1 = Encoder.md5("openolat", null);
Assert.assertEquals(openolat, hashedOpenolat_1);
String encryptedOpenolat_1 = Encoder.md5hash("openolat");
Assert.assertEquals(openolat, encryptedOpenolat_1);
String encryptedOpenolat_2 = Encoder.encrypt("openolat", null, Algorithm.md5);
Assert.assertEquals(openolat, encryptedOpenolat_2);
}
/**
* Dummy test which check that the salts are not always equals.
*/
@Test
public void testSalt() {
Set<String> history = new HashSet<String>();
for(int i=0; i<100; i++) {
String salt = Encoder.getSalt();
Assert.assertFalse(history.contains(salt));
history.add(salt);
}
Assert.assertEquals(100, history.size());
}
@Test
public void testSHA1() {
String password = "openolat#19";
String salt = "FEHq1hZYqd54/iCoboHvBQ==";
String hash = "dkpoYSfn3uz6UcwdFhauuOFgX7Q=";
String shaOutput = Encoder.encrypt(password, salt, Algorithm.sha1);
Assert.assertEquals(hash, shaOutput);
}
@Test
public void testSHA256() {
String password = "openolat#19";
String salt = "dbStjLmL2av7LObcN/69ww==";
String hash = "+iTqibtIuur1t1IBYJ3P1i/iq6Xx2cb38wHc7LXHLHQ=";
String shaOutput = Encoder.encrypt(password, salt, Algorithm.sha256);
Assert.assertEquals(hash, shaOutput);
}
@Test
public void testSHA512() {
String password = "openolat#19";
String salt = "Y4nY4VFWaiSnM6qe88ZxbQ==";
String hash = "3+OTGOdnladWlLOY71DNnYa1YpaNmrDyefCvp/LM7d417frbjabdJnWkxK6JLOwxzJkpSfyjg3LY\nY8I0Mnq8PA==";
String shaOutput = Encoder.encrypt(password, salt, Algorithm.sha512);
Assert.assertEquals(hash, shaOutput);
}
@Test
public void testPBKDF2() {
String password = "openolat#19";
String salt = "lji1/YS8rEwv/ML0JUV2OQ==";
String hash = "kUUaki27mueSEkrFeAFQoLfs1k8=";
String shaOutput = Encoder.encrypt(password, salt, Algorithm.pbkdf2);
Assert.assertEquals(hash, shaOutput);
}
@Test
public void concurrentMD5() {
final CountDownLatch finishCount = new CountDownLatch(14);
EncryptMD5Runner[] encrypters = new EncryptMD5Runner[]{
new EncryptMD5Runner("openolat#19","lji1/YS8rEwv/ML0JUV2OQ==","67895d9df8d2b3ba011c29e482e89caa", finishCount),
new EncryptMD5Runner("secret#19","zewurtuiozu","e1a9c2c4b2cdc94a1c65aa61e6a098f4", finishCount),
new EncryptMD5Runner("secret?0","9c0ff19b-4b62-4428-8fc3-08c27d9a1328","6f15a2cce20d5ee894e62dfdbc672ba2", finishCount),
new EncryptMD5Runner("secret?1","b07ff38f-6c1f-4c46-a274-12b1d5954f89","931611fa5f1163f81965ba81ebedf7a9", finishCount),
new EncryptMD5Runner("secret?2","00f8dcf6-61ee-4a47-ad95-7b0055740b2c","1c144f086be2d9001ee3fe5d431a6720", finishCount),
new EncryptMD5Runner("secret?3","32f6c9bb-b19a-422e-bb0c-51b4fd1f0196","fb0ab614ea8f448c21d58454c8683c4a", finishCount),
new EncryptMD5Runner("secret?4","e5d993ed-83a5-4521-89e0-a83c1fb7b80d","a383d8089a3cf28f5b89c7262d9237f2", finishCount),
new EncryptMD5Runner("secret?5","aabe7399-920d-4ba0-8d60-9d7ff52c272f","21db34962517f47da0fe2dd49c0027fd", finishCount),
new EncryptMD5Runner("weak?secret#0","c447d1e5-15f6-4be4-a3c8-dc673a0524c7","474c42e67c23a3cddea5519ffdf82d75", finishCount),
new EncryptMD5Runner("weak?secret#1","e1296d99-b3b4-4de6-9f9b-19fdad6e52a1","19b8d7083b0cfd1e52d647ec9ae037c8", finishCount),
new EncryptMD5Runner("weak?secret#2","3d50300e-f53e-46c0-8cd9-fa9ea1dc4887","d7cde9946e7de02e7814952829d84ca6", finishCount),
new EncryptMD5Runner("weak?secret#3","c0f6f257-8c57-4da3-b10b-5bf65bd2037e","970355c4d8f52905367a43121f062e83", finishCount),
new EncryptMD5Runner("weak?secret#4","f547c7c2-e6ae-4545-945d-99d8cb415518","70abf0cf3d63c0b96b676098bd19856d", finishCount),
new EncryptMD5Runner("weak?secret#5","b8d63092-acd5-4824-858a-200162dea348","0fa562df8d25070d9867ebeae51e24d7", finishCount),
};
for(int i=0; i<14; i++) {
encrypters[i].start();
}
try {
finishCount.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Assert.fail("Threads did not finish in 10sec");
}
for(int i=0; i<14; i++) {
Assert.assertEquals(encrypters[i].getReference(), encrypters[i].getHash());
}
}
private static class EncryptMD5Runner extends Thread {
private final CountDownLatch countDown;
private final String password;
private final String salt;
private final String reference;
private String hash;
public EncryptMD5Runner(String password, String salt, String reference, CountDownLatch countDown) {
this.salt = salt;
this.password = password;
this.reference = reference;
this.countDown = countDown;
}
public String getReference() {
return reference;
}
public String getHash() {
return hash;
}
@Override
public void run() {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
hash = Encoder.encrypt(password, salt, Algorithm.md5);
countDown.countDown();
}
}
@Test
public void concurrentPBKDF2() {
final CountDownLatch finishCount = new CountDownLatch(15);
EncryptPBKDF2Runner[] encrypters = new EncryptPBKDF2Runner[]{
new EncryptPBKDF2Runner("openolat#19", "lji1/YS8rEwv/ML0JUV2OQ==", "kUUaki27mueSEkrFeAFQoLfs1k8=", finishCount),
new EncryptPBKDF2Runner("secret#19", "zewurtuiozu", "6ZE0hrBsbs4gNMnrSSQS6TbzpuI=", finishCount),
new EncryptPBKDF2Runner("top-secret", "clearance", "JgRVHHHT29PKlwuhSbQVczBChkY=", finishCount),
new EncryptPBKDF2Runner("secret?0","fb79944a-ab0e-45ad-be1c-0eb50a2f3031","xiZw1itsZGXdFO3AeUg8Du9gbSk=", finishCount),
new EncryptPBKDF2Runner("secret?1","a78872be-5798-4120-9577-98f79f993ebc","qLtZfhh2OSGB71qOT1QoK+e3VCY=", finishCount),
new EncryptPBKDF2Runner("secret?2","94136eb8-99ac-41ab-9bc6-a534ea390492","EnygPiljxgxQPUAo+k4kPTnSEYk=", finishCount),
new EncryptPBKDF2Runner("secret?3","800617f4-80cf-4e92-a0fd-06ca8c83e5a3","osUdlhRDuGKhrtlDk7GqpmRC5rk=", finishCount),
new EncryptPBKDF2Runner("secret?4","cc4aa953-1f13-4370-a803-9388a68aa868","pa/qNiKj8SMP9bTMwZ3M7kzeFuo=", finishCount),
new EncryptPBKDF2Runner("secret?5","83634a3b-fc3d-4dc5-94c4-684063833912","ZJLaMn4xyRvieyK+xYeH4dvzI7Q=", finishCount),
new EncryptPBKDF2Runner("more?secret#0","aaade6df-3319-416d-b405-a6299cc84970","pOV6OT1aVo6oMKJj81UL5wcnpH0=", finishCount),
new EncryptPBKDF2Runner("more?secret#1","d7bc525f-5bf6-49f8-bc51-18606873de9f","isxOvmuPRk8jwwnAaUfKIyMDddc=", finishCount),
new EncryptPBKDF2Runner("more?secret#2","c9638cc5-4e27-497a-8f1d-75d0937459a7","gYSvlDb/p6bxWfVGsKTpfMQR/Ik=", finishCount),
new EncryptPBKDF2Runner("more?secret#3","69d730e1-678f-4ed0-8b98-47f098e0a200","5CPd6B0aXJB5qJoYiCe6xJZW7ug=", finishCount),
new EncryptPBKDF2Runner("more?secret#4","c0ed1714-43b7-46c8-8816-7f72ef0b9d3b","oq1tqJxIlQiKGbluqRzCAKEoxhY=", finishCount),
new EncryptPBKDF2Runner("more?secret#5","5e29f2e9-6bf2-4998-9d21-01f69f12533f","Asz/tXx96d+fIafd4ZSlEPHkay8=", finishCount)
};
for(int i=0; i<15; i++) {
encrypters[i].start();
}
try {
finishCount.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Assert.fail("Threads did not finish in 10sec");
}
for(int i=0; i<15; i++) {
Assert.assertEquals(encrypters[i].getReference(), encrypters[i].getHash());
}
}
private static class EncryptPBKDF2Runner extends Thread {
private final CountDownLatch countDown;
private final String password;
private final String salt;
private final String reference;
private String hash;
public EncryptPBKDF2Runner(String password, String salt, String reference, CountDownLatch countDown) {
this.salt = salt;
this.password = password;
this.reference = reference;
this.countDown = countDown;
}
public String getReference() {
return reference;
}
public String getHash() {
return hash;
}
@Override
public void run() {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
hash = Encoder.encrypt(password, salt, Algorithm.pbkdf2);
countDown.countDown();
}
}
}