/*
* This file is part of the OdinMS Maple Story Server Copyright (C) 2008 ~ 2010
* Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan
* Christian Meyer <vimes@odinms.de>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation. You may not use, modify or distribute this
* program under any other version of the GNU Affero General Public License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package javastory.client;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.RSAPrivateKeySpec;
import java.util.Random;
import javastory.tools.HexTool;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
public final class LoginCrypto {
private LoginCrypto() {
}
protected final static int extralength = 6;
private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private final static char[] DIGIT = "123456789".toCharArray();
private final static Random RNG = new Random();
private static KeyFactory RSAKeyFactory;
static {
Security.addProvider(new BouncyCastleProvider());
try {
RSAKeyFactory = KeyFactory.getInstance("RSA");
} catch (final NoSuchAlgorithmException nsa) {
System.err.println("[LoginCrypto] Error occured with RSA KeyFactory");
}
}
public static String Generate_13DigitAsiasoftPassport() {
final StringBuilder sb = new StringBuilder();
sb.append(ALPHABET[RNG.nextInt(ALPHABET.length)]); // First Letter
for (int i = 0; i < 11; i++) {
sb.append(DIGIT[RNG.nextInt(DIGIT.length)]); // 11 Numbers
}
sb.append(ALPHABET[RNG.nextInt(ALPHABET.length)]); // Last Letter
return sb.toString();
}
private static String toSimpleHexString(final byte[] bytes) {
return HexTool.toString(bytes).replace(" ", "").toLowerCase();
}
private static String hashWithDigest(final String in, final String digest) {
try {
final MessageDigest Digester = MessageDigest.getInstance(digest);
Digester.update(in.getBytes("US-ASCII"), 0, in.length());
final byte[] sha1Hash = Digester.digest();
return toSimpleHexString(sha1Hash);
} catch (final NoSuchAlgorithmException ex) {
throw new RuntimeException("Hashing the password failed", ex);
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException("Encoding the string failed", e);
}
}
private static String hexSha1(final String in) {
return hashWithDigest(in, "SHA-1");
}
private static String hexSha512(final String in) {
return hashWithDigest(in, "SHA-512");
}
public static boolean checkSha1Hash(final String hash, final String password) {
return hash.equals(hexSha1(password));
}
public static boolean checkSaltedSha512Hash(final String hash, final String password, final String salt) {
return hash.equals(makeSaltedSha512Hash(password, salt));
}
public static String makeSaltedSha512Hash(final String password, final String salt) {
return hexSha512(password + salt);
}
public static String makeSalt() {
final byte[] salt = new byte[16];
RNG.nextBytes(salt);
return toSimpleHexString(salt);
}
public static String padWithRandom(final String in) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < extralength; i++) {
sb.append(RNG.nextBoolean() ? ALPHABET[RNG.nextInt(ALPHABET.length)] : DIGIT[RNG.nextInt(DIGIT.length)]);
}
return sb.toString() + in;
}
public static String getPadding(final String in) {
return in.substring(extralength, extralength + 128);
}
public static String decryptRSA(final String EncryptedPassword) {
try {
final Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC");
final BigInteger modulus = new BigInteger(
"107657795738756861764863218740655861479186575385923787150128619142132921674398952720882614694082036467689482295621654506166910217557126105160228025353603544726428541751588805629215516978192030682053419499436785335057001573080195806844351954026120773768050428451512387703488216884037312069441551935633523181351");
final BigInteger privateExponent = new BigInteger(
"5550691850424331841608142211646492148529402295329912519344562675759756203942720314385192411176941288498447604817211202470939921344057999440566557786743767752684118754789131428284047255370747277972770485804010629706937510833543525825792410474569027516467052693380162536113699974433283374142492196735301185337");
final RSAPrivateKeySpec privKey1 = new RSAPrivateKeySpec(modulus, privateExponent);
final PrivateKey privKey = RSAKeyFactory.generatePrivate(privKey1);
final byte[] bytes = Hex.decode(EncryptedPassword);
cipher.init(Cipher.DECRYPT_MODE, privKey);
return new String(cipher.doFinal(bytes));
} catch (final InvalidKeyException ike) {
System.err.println("[LoginCrypto] Error initalizing the encryption cipher. Make sure you're using the Unlimited Strength cryptography jar files.");
} catch (final NoSuchProviderException nspe) {
System.err.println("[LoginCrypto] Security provider not found");
} catch (final Exception e) {
System.err.println("[LoginCrypto] Error occured with RSA password decryption.");
}
return "";
}
}