/**
* Copyright 2013-2015 Seagate Technology LLC.
*
* This Source Code Form is subject to the terms of the Mozilla
* Public License, v. 2.0. If a copy of the MPL was not
* distributed with this file, You can obtain one at
* https://mozilla.org/MP:/2.0/.
*
* This program is distributed in the hope that it will be useful,
* but is provided AS-IS, WITHOUT ANY WARRANTY; including without
* the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or
* FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public
* License for more details.
*
* See www.openkinetic.org for more project information
*/
package com.seagate.kinetic.simulator.common.lib;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.Assert;
import java.security.Key;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.crypto.spec.SecretKeySpec;
import com.google.protobuf.ByteString;
import com.seagate.kinetic.client.internal.MessageFactory;
import com.seagate.kinetic.common.lib.Hmac;
import com.seagate.kinetic.common.lib.Hmac.HmacException;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.proto.Kinetic.Command;
import com.seagate.kinetic.proto.Kinetic.Command.Body;
import com.seagate.kinetic.proto.Kinetic.Command.Header;
import com.seagate.kinetic.proto.Kinetic.Command.Status;
import com.seagate.kinetic.proto.Kinetic.Command.Status.StatusCode;
import com.seagate.kinetic.proto.Kinetic.Message;
/**
*
* Hmac test verify calculate result
* <p>
*
* @author Chenchong(Emma) Li
*
*/
@Test(groups = {"simulator"})
public class HmacTest {
private static final String DEMO_KEY = "asdfasdf";
private static final String TEST_KEY = "qwerqwer";
Key key = new SecretKeySpec(
ByteString.copyFromUtf8(DEMO_KEY).toByteArray(), "HmacSHA1");
Key key1 = new SecretKeySpec(ByteString.copyFromUtf8(TEST_KEY)
.toByteArray(), "HmacSHA1");
@BeforeMethod
public void setUp() throws Exception {
}
@AfterMethod
public void tearDown() throws Exception {
}
@Test
public void testCalcTag() throws HmacException {
KineticMessage km1 = MessageFactory.createKineticMessageWithBuilder();
KineticMessage km2 = MessageFactory.createKineticMessageWithBuilder();
Message.Builder msg1 = (Message.Builder) km1.getMessage();
Message.Builder msg2 = (Message.Builder) km2.getMessage();
Command.Builder commandBuilder1 = (Command.Builder) km1.getCommand();
Command.Builder commandBuilder2 = (Command.Builder) km2.getCommand();
Header.Builder header = commandBuilder1.getHeaderBuilder();
Body.Builder body = commandBuilder1.getBodyBuilder();
Status.Builder status = (Status.Builder) commandBuilder1
.getStatusBuilder();
Command.KeyValue.Builder kv = body.getKeyValueBuilder();
ByteString value = ByteString.copyFrom("123".getBytes());
ByteString value1 = ByteString.copyFrom("456".getBytes());
msg1.getHmacAuthBuilder().setIdentity(1);
// set header
header.setClusterVersion(1234);
header.setConnectionID(1111);
header.setSequence(1);
// set body
kv.setKey(ByteString.copyFrom("abc".getBytes()));
body.setKeyValue(kv);
// set status
status.setCode(Command.Status.StatusCode.SUCCESS);
status.setStatusMessage("message");
// assemble the message
commandBuilder1.setHeader(header);
commandBuilder1.setBody(body);
commandBuilder1.setStatus(status);
km1.setMessage(msg1);
km1.setValue(value.toByteArray());
km1.setCommand(commandBuilder1);
commandBuilder2.setHeader(header);
commandBuilder2.setBody(body);
commandBuilder2.setStatus(status);
km2.setMessage(msg2);
km2.setValue(value.toByteArray());
km2.setCommand(commandBuilder2);
ByteString hmac1 = null;
ByteString hmac2 = null;
// calculate the same message and make sure the result equal
hmac1 = Hmac.calcTag(km1, key);
hmac2 = Hmac.calcTag(km2, key);
assertTrue(Arrays.equals(hmac1.toByteArray(), hmac2.toByteArray()));
// modify the value and then calculate again
msg2.getHmacAuthBuilder().setIdentity(2);
km2.setMessage(msg2);
km2.setValue(value1.toByteArray());
hmac2 = Hmac.calcTag(km2, key);
assertFalse(Arrays.equals(hmac1.toByteArray(), hmac2.toByteArray()));
}
@Test
public void testCalc() throws HmacException {
byte[] bytes1 = "abc".getBytes();
byte[] bytes2 = "cdf".getBytes();
ByteString hmac1 = Hmac.calc(bytes1, key);
ByteString hmac2 = Hmac.calc(bytes2, key);
assertFalse(Arrays.equals(hmac1.toByteArray(), hmac2.toByteArray()));
hmac1 = Hmac.calc(bytes1, key);
hmac2 = Hmac.calc(bytes1, key1);
if (!key.equals(key1))
assertFalse(Arrays.equals(hmac1.toByteArray(), hmac2.toByteArray()));
bytes2 = "abc".getBytes();
hmac1 = Hmac.calc(bytes1, key);
hmac2 = Hmac.calc(bytes2, key);
assertTrue(Arrays.equals(hmac1.toByteArray(), hmac2.toByteArray()));
hmac1 = Hmac.calc(bytes1, key1);
hmac2 = Hmac.calc(bytes2, key1);
assertTrue(Arrays.equals(hmac1.toByteArray(), hmac2.toByteArray()));
}
@Test
public void testCheck() throws HmacException {
KineticMessage km1 = MessageFactory.createKineticMessageWithBuilder();
Message.Builder msg1 = (Message.Builder) km1.getMessage();
Command.Builder commandBuilder1 = (Command.Builder) km1.getCommand();
Header.Builder header1 = commandBuilder1.getHeaderBuilder();
Body.Builder body1 = commandBuilder1.getBodyBuilder();
Status.Builder status1 = (Status.Builder) commandBuilder1
.getStatusBuilder();
Command.KeyValue.Builder kv1 = body1.getKeyValueBuilder();
ByteString value1 = ByteString.copyFrom("123".getBytes());
msg1.getHmacAuthBuilder().setIdentity(1);
header1.setClusterVersion(1234);
header1.setConnectionID(1111);
header1.setSequence(1);
body1.setKeyValue(kv1.setKey(ByteString.copyFrom("abc".getBytes())));
status1.setCode(StatusCode.SUCCESS);
status1.setStatusMessage("message");
commandBuilder1.setHeader(header1);
commandBuilder1.setBody(body1);
commandBuilder1.setStatus(status1);
// get command bytes for hmac calculation
byte[] commandBytes = commandBuilder1.build().toByteString()
.toByteArray();
// set command bytes to message
msg1.setCommandBytes(ByteString.copyFrom(commandBytes));
km1.setValue(value1.toByteArray());
km1.setCommand(commandBuilder1.build());
km1.setMessage(msg1);
byte[] bytes = km1.getMessage().getCommandBytes().toByteArray();
ByteString expected = Hmac.calc(bytes, key);
assertTrue(Hmac.check(bytes, key, expected));
msg1.getHmacAuthBuilder().setHmac(expected);
assertTrue(Hmac.check(km1, key));
body1.setKeyValue(kv1.setKey(ByteString.copyFrom("def".getBytes())));
commandBuilder1.setBody(body1);
commandBytes = commandBuilder1.build().toByteString().toByteArray();
msg1.setCommandBytes(ByteString.copyFrom(commandBytes));
km1.setCommand(commandBuilder1.build());
byte[] bytes1 = km1.getMessage().getCommandBytes().toByteArray();
ByteString expected1 = Hmac.calc(bytes1, key);
msg1.getHmacAuthBuilder().setHmac(expected1);
assertTrue(Hmac.check(bytes1, key, expected1));
assertTrue(Hmac.check(km1, key));
assertFalse(Arrays.equals(expected.toByteArray(),
expected1.toByteArray()));
}
@Test
public void concurrentHmacCalcTest() throws InterruptedException {
int writeThreads = 3;
int writesEachThread = 5;
ExecutorService pool = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(writeThreads);
for (int i = 0; i < writeThreads; i++) {
pool.execute(new WriteThread(writesEachThread, latch));
}
latch.await();
pool.shutdown();
}
class WriteThread implements Runnable {
private int writeCount = 0;
private final CountDownLatch latch;
public WriteThread(int writeCount, CountDownLatch latch) {
this.writeCount = writeCount;
this.latch = latch;
}
@Override
public void run() {
KineticMessage km1 = MessageFactory
.createKineticMessageWithBuilder();
Message.Builder msg1 = (Message.Builder) km1.getMessage();
Command.Builder commandBuilder1 = (Command.Builder) km1
.getCommand();
Header.Builder header1 = commandBuilder1.getHeaderBuilder();
Body.Builder body1 = commandBuilder1.getBodyBuilder();
Status.Builder status1 = (Status.Builder) commandBuilder1
.getStatusBuilder();
Command.KeyValue.Builder kv1 = body1.getKeyValueBuilder();
ByteString value1 = ByteString.copyFrom("123".getBytes());
msg1.getHmacAuthBuilder().setIdentity(1);
header1.setClusterVersion(1234);
header1.setConnectionID(1111);
header1.setSequence(1);
body1.setKeyValue(kv1.setKey(ByteString.copyFrom("abc".getBytes())));
status1.setCode(StatusCode.SUCCESS);
status1.setStatusMessage("message");
commandBuilder1.setHeader(header1);
commandBuilder1.setBody(body1);
commandBuilder1.setStatus(status1);
byte[] commandBytes = commandBuilder1.build().toByteString()
.toByteArray();
// set command bytes to message
msg1.setCommandBytes(ByteString.copyFrom(commandBytes));
km1.setValue(value1.toByteArray());
km1.setCommand(commandBuilder1.build());
km1.setMessage(msg1);
byte[] bytes1 = km1.getMessage().getCommandBytes().toByteArray();
for (int i = 0; i < writeCount; i++) {
try {
header1.setAckSequence((int) (10 * Math.random()));
commandBuilder1.setHeader(header1);
Hmac.calc(bytes1, key);
} catch (HmacException e) {
Assert.fail("calc hmac failed: " + e.getMessage());
}
}
latch.countDown();
}
}
@Test
public void loopHmacTest() {
KineticMessage km1 = MessageFactory.createKineticMessageWithBuilder();
Message.Builder msg1 = (Message.Builder) km1.getMessage();
Command.Builder commandBuilder1 = (Command.Builder) km1.getCommand();
Header.Builder header1 = commandBuilder1.getHeaderBuilder();
Body.Builder body1 = commandBuilder1.getBodyBuilder();
Status.Builder status1 = (Status.Builder) commandBuilder1
.getStatusBuilder();
Command.KeyValue.Builder kv1 = body1.getKeyValueBuilder();
ByteString value1 = ByteString.copyFrom("123".getBytes());
msg1.getHmacAuthBuilder().setIdentity(1);
header1.setClusterVersion(1234);
header1.setConnectionID(1111);
header1.setSequence(1);
body1.setKeyValue(kv1.setKey(ByteString.copyFrom("abc".getBytes())));
status1.setCode(StatusCode.SUCCESS);
status1.setStatusMessage("message");
commandBuilder1.setHeader(header1);
commandBuilder1.setBody(body1);
commandBuilder1.setStatus(status1);
byte[] commandBytes = commandBuilder1.build().toByteString()
.toByteArray();
// set command bytes to message
msg1.setCommandBytes(ByteString.copyFrom(commandBytes));
km1.setValue(value1.toByteArray());
km1.setCommand(commandBuilder1.build());
km1.setMessage(msg1);
byte[] bytes1 = km1.getMessage().getCommandBytes().toByteArray();
int totalLoopCount = 100;
for (int i = 0; i < totalLoopCount; i++) {
try {
Hmac.calc(bytes1, key);
} catch (HmacException e) {
Assert.fail("Hamc calc throw exception: " + e.getMessage());
}
}
}
@Test
public void hmacWithTagTest() {
KineticMessage km1 = MessageFactory.createKineticMessageWithBuilder();
KineticMessage km2 = MessageFactory.createKineticMessageWithBuilder();
Message.Builder msg1 = (Message.Builder) km1.getMessage();
Command.Builder commandBuilder1 = (Command.Builder) km1.getCommand();
Header.Builder header1 = commandBuilder1.getHeaderBuilder();
Body.Builder body1 = commandBuilder1.getBodyBuilder();
Status.Builder status1 = (Status.Builder) commandBuilder1
.getStatusBuilder();
Command.KeyValue.Builder kv1 = body1.getKeyValueBuilder();
kv1.setKey(ByteString.copyFrom("123".getBytes()));
kv1.setTag(ByteString.copyFrom("tag".getBytes()));
ByteString value1 = ByteString.copyFrom("123".getBytes());
ByteString value2 = ByteString.copyFrom("456".getBytes());
msg1.getHmacAuthBuilder().setIdentity(1);
header1.setClusterVersion(1234);
header1.setConnectionID(1111);
header1.setSequence(1);
body1.setKeyValue(kv1);
status1.setCode(StatusCode.SUCCESS);
status1.setStatusMessage("message");
commandBuilder1.setHeader(header1);
commandBuilder1.setBody(body1);
commandBuilder1.setStatus(status1);
byte[] commandBytes = commandBuilder1.build().toByteString()
.toByteArray();
// set command bytes to message
msg1.setCommandBytes(ByteString.copyFrom(commandBytes));
km1.setValue(value1.toByteArray());
km1.setCommand(commandBuilder1.build());
km1.setMessage(msg1);
byte[] bytes1 = km1.getMessage().getCommandBytes().toByteArray();
km2.setValue(value2.toByteArray());
km2.setCommand(commandBuilder1.build());
km2.setMessage(msg1);
byte[] bytes2 = km2.getMessage().getCommandBytes().toByteArray();
ByteString hmacWithTag = null;
ByteString hmacWithTag1 = null;
try {
hmacWithTag = Hmac.calc(bytes1, key);
} catch (HmacException e) {
Assert.fail("Hmac calc throw exception: " + e.getMessage());
}
try {
hmacWithTag1 = Hmac.calc(bytes2, key);
} catch (HmacException e) {
Assert.fail("Hmac calc throw exception: " + e.getMessage());
}
assertTrue(Arrays.equals(hmacWithTag.toByteArray(),
hmacWithTag1.toByteArray()));
}
}