Commit 7cfca8a9 authored by Josh Ji's avatar Josh Ji

ask id v2, docker compose, hkdf, hmac

parent 542a0033
FROM maven AS build
COPY . /tmp
WORKDIR /tmp
RUN mvn clean package -DskipTests
#FROM maven AS build
#COPY . /tmp
#WORKDIR /tmp
#RUN mvn clean package -DskipTests
FROM openjdk:11-jre-slim
COPY --from=build /tmp/target/*.jar app.jar
#COPY --from=build /tmp/target/*.jar app.jar
COPY target/*.jar app.jar
EXPOSE 8086
ENV SPRING_DATASOURCE_USERNAME=root
ENV SPRING_DATASOURCE_PASSWORD=rootpasswd
......
services:
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: idp
MYSQL_USER: idp
MYSQL_PASSWORD: idppasswd
volumes:
- "./Dump20231106.sql:/docker-entrypoint-initdb.d/1.sql"
ports:
- 32306:3306
rpserver:
image: rpserver
environment:
IDP_URL: http://idpserver:8086/
ports:
- 443:443
idpserver:
image: idpserver
environment:
SPRING_DATASOURCE_USERNAME: idp
SPRING_DATASOURCE_PASSWORD: idppasswd
SPRING_DATASOURCE_URL: jdbc:mysql://mysql/idp
ports:
- 8086:8086
networks:
overlay:
driver: overlay
\ No newline at end of file
......@@ -12,9 +12,6 @@ import org.springframework.web.bind.annotation.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;
......@@ -22,11 +19,11 @@ import java.util.Map;
@RestController
@RequestMapping("/api")
public class RESTfulApi {
public class askIdentity {
@Autowired
JdbcTemplate jdbcTemplate = new JdbcTemplate();
Logger logger = LoggerFactory.getLogger(RESTfulApi.class);
Logger logger = LoggerFactory.getLogger(askIdentity.class);
@PostMapping("/idp/askIdentity")
......
package com.prlab.idpserver.controller;
import com.prlab.idpserver.hkdf.HKDF;
import com.prlab.idpserver.model.IdentityRequestV2;
import org.apache.tomcat.util.buf.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@RestController
@RequestMapping("/api")
public class askIdentityV2 {
@Autowired
JdbcTemplate jdbcTemplate = new JdbcTemplate();
Logger logger = LoggerFactory.getLogger(askIdentityV2.class);
@PostMapping("/idp/askIdentityV2")
public String queryIdentity(@RequestBody IdentityRequestV2 r){
logger.info("r : {}, {}, {}, {}", r.nonce_base64, r.idHash_base64, r.cE_base64, r.HMAC_base64);
byte[] nonce = Base64Utils.decodeFromString(r.nonce_base64);
byte[] idHash = Base64Utils.decodeFromString(r.idHash_base64);
byte[] cE = Base64Utils.decodeFromString(r.cE_base64);
byte[] hmac = Base64Utils.decodeFromString(r.HMAC_base64);
logger.info("nonce: {}\nidHash: {}\ncE: {}\nhmac: {}\n",
HexUtils.toHexString(nonce),
HexUtils.toHexString(idHash),
HexUtils.toHexString(cE),
HexUtils.toHexString(hmac)
);
String sql_query_by_id_hash ="select * from pivinfo " +
"where hex(?)=sha2(unhex(concat(sha2(id, 256), sha2(?, 256))), 256) limit 1;" ;
// String sql_query_by_id_hash = "SELECT * FROM users " +
// "WHERE hex(?)=sha2(unhex(concat(sha2(uid, 256), sha2(?, 256))), 256)";
long t1 = System.currentTimeMillis();
List<Map<String, Object>> list =
jdbcTemplate.queryForList(sql_query_by_id_hash,
new Object[]{
Base64Utils.decodeFromString(r.idHash_base64),
Base64Utils.decodeFromString(r.nonce_base64)},
new int[]{Types.VARBINARY, Types.VARBINARY});
long t2 = System.currentTimeMillis();
logger.info("time consumed: {} ms", t2-t1);
BigInteger nonceInt = new BigInteger(nonce);
BigInteger nonceInt1 = nonceInt.add(new BigInteger(String.valueOf(1)));
AtomicReference<String> msg = new AtomicReference<>("Your Identity is Invalid.," + (t2 - t1));
list.forEach(map->{
String id = (String)map.get("id");
try {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] idSha256 = sha256.digest(id.getBytes(StandardCharsets.UTF_8));
byte[] nonce1Sha256 = sha256.digest(nonceInt1.toByteArray());
sha256.update(idSha256);
byte[] idHash1 = sha256.digest(nonce1Sha256);
byte[] counter = new byte[cE.length];
xor(cE, idHash1, counter);
ByteBuffer byteBuffer = ByteBuffer.allocate(Long.BYTES); // uint32 to int64(long)
byteBuffer.put(new byte[4]);
byteBuffer.put(counter);
byteBuffer.rewind();
long c = byteBuffer.getLong();
logger.info("id: {}",id);
logger.info("c: {}",c);
HKDF hkdf = new HKDF((byte[])map.get("sharedSecret"), (byte[])map.get("hkdf_chain_iv"), c);
long t3 = System.nanoTime();
byte[] outputKey = hkdf.getOutputKey(((String)map.get("id")).getBytes(StandardCharsets.UTF_8), 32);
long t4 = System.nanoTime();
logger.info("t4-t3: {}", t4-t3);
Mac h256 = Mac.getInstance("HmacSHA256");
h256.init(new SecretKeySpec(outputKey, "HmacSHA256"));
byte[] hmac_ = h256.doFinal(idHash);
print("hmac_", hmac_);
print("hmac", hmac);
if(Arrays.equals(hmac, hmac_)){
logger.info("hmac is correct");
msg.set("Your Identity is Valid.," + (t2 - t1));
}
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
});
if(list.size()>0)
// return (String)list.get(0).get("id");
return msg.get();
else
return "IDENTITY_NOT_FOUND";
}
public void xor(byte[] a, byte[] b, byte[] output){
for(short i = 0; i< a.length; i++){
output[i] = (byte)(a[i] ^ b[i]);
}
}
public void print(byte[] data){
logger.info(HexUtils.toHexString(data));
}
public void print(String tag, byte[] data){
logger.info("{}: {}", tag, HexUtils.toHexString(data));
}
}
package com.prlab.idpserver.hkdf;
import javax.crypto.SecretKey;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
public class HKDF {
private final byte[] key;
private final byte[] iv;
private long iterate;
private HMAC hmac;
public HKDF(byte[] key, byte[] iv, long iterate ) throws NoSuchAlgorithmException {
this.key = key;
this.iv = iv;
this.iterate = iterate;
this.hmac = new HMAC(key);
}
private byte[] extract(byte[] salt, byte[] ikm) throws NoSuchAlgorithmException {
hmac.setKey(salt);
hmac.update(ikm);
return hmac.doFinal();
}
private byte[] expand(byte[] prk, byte[] info, int outLengthBytes) throws NoSuchAlgorithmException{
// sha256 maclength is always 32
int n = (int) Math.ceil(((double) outLengthBytes) / ((double) 32));
if( n > 255) {
throw new IllegalArgumentException("out length must be maximal 255 * hash-length; requested: " + outLengthBytes + " bytes");
}
byte[] blockN;
byte[] ret = new byte[outLengthBytes];
int stepSize = 0;
int remainingBytes = outLengthBytes;
for(int i = 0; i < n; i++ ){
hmac.setKey(prk);
hmac.update(info);
byte[] counter = {(byte)(i+1)};
hmac.update(counter);
blockN = hmac.doFinal();
stepSize = blockN.length;
if(stepSize < remainingBytes){
arrayCopy(ret, blockN, outLengthBytes-remainingBytes, stepSize);
remainingBytes -= stepSize;
}else{
arrayCopy(ret, blockN, outLengthBytes - remainingBytes, remainingBytes);
}
}
return ret;
}
public byte[] getPRK() throws NoSuchAlgorithmException{
byte[] prf = this.iv;
for( long i=0 ; i < this.iterate; i++ ){
prf = extract(prf, this.key);
}
return prf;
}
public byte[] getOutputKey(byte[] info, int outLengthBytes) throws NoSuchAlgorithmException{
byte[] outputKey;
byte[] salt = this.iv;
for( long i = 0; i < this.iterate; i++){
salt = extract(salt, this.key);
}
outputKey = expand(salt, info, outLengthBytes);
return outputKey;
}
private static void arrayCopy(byte[] arr1, byte[] arr2, int start, int offset){
for(int i = 0; i < offset; i++ ){
arr1[start+i] = arr2[i];
}
}
}
package com.prlab.idpserver.hkdf;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HMAC {
private byte[] key;
private byte[] msg;
private byte[] opad = new byte[64];
private byte[] ipad = new byte[64];
public HMAC(byte[] key) throws NoSuchAlgorithmException {
setKey(key);
for (int i = 0; i < opad.length; ++i) {
opad[i] = 0x5c;
ipad[i] = 0x36;
}
}
public void setKey(byte[] key) throws NoSuchAlgorithmException {
if(key == null){
return;
}
else if(key.length < 64){
this.key = padding(key, 64);
}
else{
this.key = hash(key);
}
}
public void update(byte[] m ){
if(this.msg == null){
this.msg = m;
}
else{
this.msg = concat(this.msg, m);
}
}
// force use SHA256
public byte[] doFinal() throws NoSuchAlgorithmException{
byte[] output = hash(concat(xor(this.key, opad), hash((concat(xor(this.key, ipad), this.msg)))));
this.msg = null;
return output;
}
private byte[] padding(byte[] key, int length){
byte[] ret = new byte[length];
for(int i = 0; i < length; i++){
if(i >= key.length){
ret[i] = 0;
}
else{
ret[i] = key[i];
}
}
return ret;
}
public static byte[] xor(byte[] a, byte[] b) {
byte[] result = new byte[Math.max(a.length, b.length)];
for (int i = 0; i < result.length; ++i) {
result[i] = (byte) (0xff & ((int) a[i] ^ (int) b[i]));
}
return result;
}
public static byte[] concat(byte[] a, byte[] b){
byte[] ret = new byte[a.length + b.length];
for (int i = 0; i < a.length; i++){
ret[i] = a[i];
}
for(int i = 0; i < b.length; i ++){
ret[ i + a.length ] = b[i];
}
return ret;
}
private byte[] hash(byte[] m) throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("SHA-256");
return md.digest(m);
}
}
package com.prlab.idpserver.model;
public class IdentityRequestV2 {
public String nonce_base64;
public String idHash_base64;
public String cE_base64;
public String HMAC_base64;
}
......@@ -27,8 +27,8 @@ DROP TABLE IF EXISTS `identities`;
CREATE TABLE `identities` (
`SerialNumber` int NOT NULL AUTO_INCREMENT,
`IDx` varchar(64) COLLATE utf8_bin NOT NULL,
`HMAC` varbinary(32) NOT NULL,
`HMACbase64` varchar(45) COLLATE utf8_bin DEFAULT 'None',
`HMAC` varbinary(64) NOT NULL,
`HMACbase64` varchar(100) COLLATE utf8_bin DEFAULT 'None',
`Cx` varbinary(16) NOT NULL,
`SharedSecret` varbinary(32) NOT NULL,
`PuKx` varbinary(128) NOT NULL,
......@@ -45,7 +45,7 @@ CREATE TABLE `identities` (
LOCK TABLES `identities` WRITE;
/*!40000 ALTER TABLE `identities` DISABLE KEYS */;
INSERT INTO `identities` VALUES (29,'prlab',_binary '\Ym? Ci.XX\4|trؖ+\','vbeOm85Z8W0/IENpDi5YWOs0sr60fKV0hHL92JYrkds=',_binary '+;Кv\(\\',_binary 'w\Rm\FaC\\v/\\FSknC',_binary 'ECK1 \0\0\02+/\\\\6\6\\LUc~|y\\A\\_e\(Dg\Q\&\B5j-Ӭ\\\^B',_binary 'ECK1 \0\0\0g{\\>z \\8\\AD@W\\t >f \rN^K\?:3;9X\!f',_binary '0w \5/}H\\rH_CtInr{V\r\\o\n*H\=DB\0g{\'Ӗ\>z \\8\\AD@W\\t >f \rN^K\?:3;9X\!f');
INSERT INTO `identities` VALUES (29,'prlab',_binary '����\�Y�m? Ci.XX\�4���|�t�r�ؖ+�\�','vbeOm85Z8W0/IENpDi5YWOs0sr60fKV0hHL92JYrkds=',_binary '�+;К��v\�(�\�\�',_binary '�w\�R�m\�Fa�C�\�\�v�/\�\�FS�k��nC',_binary 'ECK1 \0\0\02�+/�\�\�\�\�6�\��6�\�\�L�Uc~|���y\�\�A\\_e\�(Dg\�Q\���&\�B5j�-Ӭ\�\�\�^�B',_binary 'ECK1 \0\0\0g{\'Ӗ\�>����z \��\�8�\�\�A�D@W\�\�t� �>f� �\rN^K\�?�:3;�9X\�!f',_binary '0w �\�5�/}H��\�\r����H_Ct��In�r{�V\r\\o�\n*�H\�=�DB\0g{\'Ӗ\�>����z \��\�8�\�\�A�D@W\�\�t� �>f� �\rN^K\�?�:3;�9X\�!f');
/*!40000 ALTER TABLE `identities` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment