Skip to content

Commit

Permalink
Fixes the HMAC Authentication of RESTv2
Browse files Browse the repository at this point in the history
Two problems prevented the authentication:
- the password deciphering expected a string and not an hex string (as returned
  by the database), which caused padding exceptions
- the HMAC sum comparison was done in bytes instead of strings, which somehow
  returned false
  • Loading branch information
Bruno Carlin authored and fredericBregier committed May 29, 2020
1 parent 90ddc15 commit 4d2d9e4
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 21 deletions.
14 changes: 14 additions & 0 deletions WaarpCommon/src/main/java/org/waarp/common/crypto/KeyObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,20 @@ public String decryptHexInString(String ciphertext) throws Exception {
return new String(decryptHexInBytes(ciphertext), WaarpStringUtils.UTF8);
}

/**
* Decrypt a String as HEX format representing a crypted String and
* returns the uncrypted String
*
* @param ciphertext
*
* @return the uncrypted String
*
* @throws Exception
*/
public String decryptHexInString(byte[] ciphertext) throws Exception {
return new String(decryptHexInBytes(ciphertext), WaarpStringUtils.UTF8);
}

/**
* Decode from a file containing a HEX crypted string
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ public void simpleTest() {
}
}

@Test
public void testDecryptHexInString() throws Exception {
final INSTANCES keyAlgo = INSTANCES.DES;
final DynamicKeyObject dyn = new DynamicKeyObject(
keyAlgo.size, keyAlgo.name(), keyAlgo.name(), keyAlgo.name()
);

dyn.generateKey();
final String original = "mypassword";
final byte[] crypted = dyn.crypt(original);
final String cryptedHex = dyn.encodeHex(crypted);
final String decrypted = dyn.decryptHexInString(cryptedHex);

assertEquals("decrypted password should be equal to the original", original, decrypted);
}

/**
* test function
*
Expand Down Expand Up @@ -99,4 +115,4 @@ private static void test(String plaintext, int size, String algo)
System.out.println(algo + ": Total time: " + (time2 - time1) + " ms, " +
nb * 1000 / (time2 + 1 - time1) + " crypt or decrypt/s");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ private boolean checkContentType(HttpRequest request,
* @throws NotAllowedException if the user making the request does
* not exist
*/
private String checkCredentials(HttpRequest request) {
protected String checkCredentials(HttpRequest request) {

final String authorization = request.headers().get(AUTHORIZATION);

Expand Down Expand Up @@ -375,32 +375,38 @@ private String checkCredentials(HttpRequest request) {
DAOFactory.closeDAO(hostDAO);
}

String pswd;
try {
pswd = configuration.getCryptoKey().decryptInString(host.getHostkey());
} catch (final Exception e) {
throw new InternalServerErrorException(
"An error occurred when decrypting the password", e);
}

String key;
try {
key = hmac.cryptToHex(authDate + authUser + pswd);
} catch (final Exception e) {
throw new InternalServerErrorException(
"An error occurred when hashing the key", e);
}

if (Arrays.equals(key.getBytes(), authKey.getBytes())) {
throw new NotAllowedException("Invalid password.");
}
validateHMACCredentials(host, authDate, authUser, authKey);

return authUser;
}

throw new NotAllowedException("Missing credentials.");
}

protected void validateHMACCredentials(Host host, String authDate,
String authUser, String authKey)
throws InternalServerErrorException {
String pswd;
try {
pswd = configuration.getCryptoKey().decryptHexInString(host.getHostkey());
} catch (final Exception e) {
throw new InternalServerErrorException(
"An error occurred when decrypting the password", e);
}

String key;
try {
key = hmac.cryptToHex(authDate + authUser + pswd);
} catch (final Exception e) {
throw new InternalServerErrorException(
"An error occurred when hashing the key", e);
}

if (!key.equals(authKey)) {
throw new NotAllowedException("Invalid password.");
}
}

/**
* Checks if the user given as argument is authorized to call the given
* method.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.waarp.openr66.protocol.http.restv2.resthandlers;

import org.junit.Test;
import org.waarp.common.crypto.Des;
import org.waarp.common.crypto.DynamicKeyObject;
import org.waarp.common.crypto.HmacSha256;
import org.waarp.openr66.pojo.Host;
import org.waarp.openr66.protocol.configuration.Configuration;

import static org.junit.Assert.fail;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.ws.rs.InternalServerErrorException;

/**
* RestHandlerHook
*/
public class RestHandlerHookTest {

public static final class RestHandlerHookForTest extends RestHandlerHook {
public RestHandlerHookForTest(final boolean authenticated,
final HmacSha256 hmac, final long delay) {
super(authenticated, hmac, delay);
}

public void testValidateHMACredentials(Host host, String authDate,
String authUser, String authKey)
throws InternalServerErrorException {
validateHMACCredentials(host, authDate, authUser, authKey);
}
}

@Test
public void testCheckCredentialsWithHMAC() throws Exception{
final HmacSha256 hmac = new HmacSha256();
hmac.generateKey();

final Des dyn = new Des();
dyn.generateKey();
Des oldKey = Configuration.configuration.getCryptoKey();
Configuration.configuration.setCryptoKey(dyn);

final String user = "user";
final String password = "mypassword";
final String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX").format(new Date());

try {

final String hostkey = dyn.cryptToHex(password);
final String sig = hmac.cryptToHex(timestamp + user + password);

final RestHandlerHookForTest hook = new RestHandlerHookForTest(true, hmac, 10000);

try {
final Host host = new Host(user, "127.0.0.1", 1, hostkey.getBytes(), false, true);

hook.testValidateHMACredentials(host, timestamp, user, sig);
} catch (InternalServerErrorException e) {
System.out.println(e);
fail("credentials validation failed, it should have succeeded");
}

} finally {
Configuration.configuration.setCryptoKey(oldKey);
}

}
}
2 changes: 2 additions & 0 deletions doc/waarp-r66/source/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Correctifs
request [`#38 <https://github.com/waarp/Waarp-All/pull/38>`__])
- Correction de la signature des requêtes dans l'API REST v2 (pull
request [`#42 <https://github.com/waarp/Waarp-All/pull/42>`__])
- Correction de l'authentification HMAC de l'API REST v2 (pull
request [`#43 <https://github.com/waarp/Waarp-All/pull/43>`__])

Waarp R66 3.3.3 (2020-05-07)
============================
Expand Down

0 comments on commit 4d2d9e4

Please sign in to comment.