/******************************************************************************
* *
* Copyright 2016 Subterranean Security *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*****************************************************************************/
package com.subterranean_security.crimson.core.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import com.google.protobuf.InvalidProtocolBufferException;
import com.subterranean_security.crimson.core.misc.AuthenticationGroup;
import com.subterranean_security.crimson.core.proto.Misc.AuthMethod;
import com.subterranean_security.crimson.core.proto.Misc.Outcome;
public final class CryptoUtil {
private CryptoUtil() {
}
public static String hash(String type, char[] target) throws NoSuchAlgorithmException {
byte[] t = toBytes(target);
MessageDigest digest;
digest = MessageDigest.getInstance(type);
digest.update(t);
byte messageDigest[] = digest.digest();
Arrays.fill(t, (byte) 0);
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++)
hexString.append(String.format("%02X", 0xFF & messageDigest[i]));
return hexString.toString().toLowerCase();
}
private static byte[] hash(String type, byte[] target) throws NoSuchAlgorithmException {
MessageDigest digest;
digest = MessageDigest.getInstance(type);
digest.update(target);
return digest.digest();
}
private static String hash(String type, String target) throws NoSuchAlgorithmException {
byte messageDigest[] = hash(type, target.getBytes());
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++)
hexString.append(String.format("%02X", 0xFF & messageDigest[i]));
return hexString.toString().toLowerCase();
}
public static String hashCrimsonPassword(String pass, String salt) {
return hashCrimsonPassword(pass.toCharArray(), salt);
}
public static String hashCrimsonPassword(char[] pass, String salt) {
byte[] hash = (new String(pass) + salt).getBytes(StandardCharsets.UTF_16);
try {
for (int i = 0; i < 999; i++) {
hash = hash("SHA-256", hash);
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new String(B64Util.encode(hash));
}
public static String hashOpencartPassword(String pass, String salt) {
try {
return hash("SHA-1", salt + hash("SHA-1", salt + hash("SHA-1", pass)));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static String genSalt() {
return RandomUtil.randString(8);
}
public static String hashSign(String magic, String key) {
try {
return new String(B64Util.encode(hash("SHA-256", (magic + key).getBytes())));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return RandomUtil.randString(8);
}
public static String hashSign(String magic, byte[] key) {
return hashSign(magic, new String(key));
}
public static String signGroupChallenge(String magic, byte[] key) {
try {
PrivateKey pkey = KeyFactory.getInstance("DSA").generatePrivate(new PKCS8EncodedKeySpec(key));
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initSign(pkey);
dsa.update(magic.getBytes());
return new String(B64Util.encode(dsa.sign()));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static boolean verifyGroupChallenge(String magic, byte[] key, String signature) {
try {
PublicKey pkey = KeyFactory.getInstance("DSA").generatePublic(new X509EncodedKeySpec(key));
Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
dsa.initVerify(pkey);
dsa.update(magic.getBytes());
return dsa.verify(B64Util.decode(signature));
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
private static final int seedSuffixLength = 128;
public static AuthenticationGroup generateGroup(String name, byte[] seedPrefix) {
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
byte[] seed = new byte[seedPrefix.length + seedSuffixLength];
for (int i = 0; i < seedPrefix.length; i++) {
seed[i] = seedPrefix[i];
}
byte[] seedSuffix = SecureRandom.getSeed(seedSuffixLength);
for (int i = 0; i < seedSuffix.length; i++) {
seed[seedPrefix.length + i] = seedSuffix[i];
}
RandomUtil.clearByte(seedSuffix);
RandomUtil.clearByte(seedPrefix);
random.setSeed(seed);
generator.initialize(1024, random);
KeyPair pair = generator.generateKeyPair();
return new AuthenticationGroup(name, pair.getPrivate(), pair.getPublic());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Outcome exportGroup(AuthMethod am, File output) {
try {
PrintWriter pw = new PrintWriter(output);
pw.println(B64Util.encode(am.toByteArray()));
pw.close();
} catch (FileNotFoundException e) {
return Outcome.newBuilder().setResult(false).setComment(e.getMessage()).build();
}
return Outcome.newBuilder().setResult(true).build();
}
public static AuthMethod importGroup(File input) {
try (BufferedReader br = new BufferedReader(new FileReader(input))) {
return AuthMethod.parseFrom(B64Util.decode(br.readLine()));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static byte[] toBytes(char[] chars) {
CharBuffer charBuffer = CharBuffer.wrap(chars);
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
Arrays.fill(charBuffer.array(), '\u0000');
Arrays.fill(byteBuffer.array(), (byte) 0);
return bytes;
}
}