Java tutorial
/******************************************************************************* * Copyright (C) 2013 JMaNGOS <http://jmangos.org/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * 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 General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.jmangos.auth.wow.controller; import java.math.BigInteger; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashMap; import org.apache.commons.lang.ArrayUtils; import org.jmangos.auth.entities.AccountEntity; import org.jmangos.auth.utils.AccountUtils; import org.jmangos.auth.wow.services.AccountService; import org.jmangos.commons.model.AccountInfo; import org.jmangos.commons.model.WoWAuthResponse; import org.jmangos.commons.model.container.AccountsContainer; import org.jmangos.commons.network.model.NettyNetworkChannel; import org.jmangos.commons.utils.BigNumber; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class AccountController { /** The Constant logger. */ private static final Logger logger = LoggerFactory.getLogger(AccountController.class); @Autowired private AccountService accountService; private final AccountsContainer accounts = new AccountsContainer(); /** * Login. * * @param name * the name * @param channelHandler * the channel handler * @return the wow auth response */ public WoWAuthResponse loadLogin(final String name, final NettyNetworkChannel channelHandler) { // if // (BannedIpController.isBanned(channelHandler.getAddress().getAddress().getHostAddress())) // { // return WoWAuthResponse.WOW_FAIL_BANNED; // } final AccountEntity accountEntity = this.accountService.readAccountByUserName(name); if (accountEntity != null) { final AccountInfo account = new AccountInfo(accountEntity.getId()); HashMap<String, BigNumber> variable; // calculateVSFields will // create it. BigNumber s = new BigNumber(); BigNumber v = new BigNumber(); channelHandler.setChanneledObject(account); if ((accountEntity.getV().length() != (32 * 2)) || (accountEntity.getS().length() != (32 * 2))) { variable = AccountUtils.calculateVSFields(accountEntity.getShaPasswordHash()); s = variable.get("s"); v = variable.get("v"); accountEntity.setS(s.asHexStr()); accountEntity.setV(v.asHexStr()); } else { s.setHexStr(accountEntity.getS()); v.setHexStr(accountEntity.getV()); } final BigNumber B = AccountUtils.getB(v, channelHandler); account.setName(name); account.setB_crypto(B); account.sets(s); account.setV_crypto(v); account.setAccessLevel(accountEntity.getGmlevel()); this.accounts.addObject(account); accountEntity.setLastIp(channelHandler.getAddress().getAddress().getHostAddress()); this.accountService.createOrUpdateAccount(accountEntity); return WoWAuthResponse.WOW_SUCCESS; } else { return WoWAuthResponse.WOW_FAIL_UNKNOWN_ACCOUNT; } } public WoWAuthResponse checkPassword(final AccountInfo account, final byte[] a, final byte[] m1) { logger.debug("a length " + a.length); logger.debug("a value " + new BigInteger(1, a).toString(16).toUpperCase()); logger.debug("m1 length " + m1.length); logger.debug("m1 value " + new BigInteger(1, m1).toString(16).toUpperCase()); MessageDigest sha = null; try { sha = MessageDigest.getInstance("SHA-1"); } catch (final NoSuchAlgorithmException e) { e.printStackTrace(); return WoWAuthResponse.WOW_FAIL_INCORRECT_PASSWORD; } final BigNumber B = account.getcryptoB(); logger.debug("B value " + B.asHexStr()); sha.update(a); sha.update(B.asByteArray(32)); final BigNumber u = new BigNumber(); u.setBinary(sha.digest()); logger.debug("u value" + u.asHexStr()); final BigNumber A = new BigNumber(); A.setBinary(a); logger.debug("A:" + A.asHexStr()); final BigNumber S = A.multiply((account.getV_crypto().modPow(u, AccountUtils.N))).modPow(account.getB(), AccountUtils.N); final byte[] t1 = new byte[16]; final byte[] vK = new byte[40]; final byte[] t = S.asByteArray(32); for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2]; } sha.update(t1); byte[] t2 = sha.digest(); for (int i = 0; i < 20; ++i) { vK[i * 2] = t2[i]; } for (int i = 0; i < 16; ++i) { t1[i] = t[(i * 2) + 1]; } sha.update(t1); t2 = sha.digest(); for (int i = 0; i < 20; ++i) { vK[(i * 2) + 1] = t2[i]; } byte[] hash = new byte[20]; logger.debug("N:" + AccountUtils.N.asHexStr()); sha.update(AccountUtils.N.asByteArray(32)); hash = sha.digest(); logger.debug("hash:" + new BigInteger(1, hash).toString(16).toUpperCase()); sha.update(AccountUtils.g.asByteArray(1)); final byte[] gH = sha.digest(); for (int i = 0; i < 20; ++i) { hash[i] ^= gH[i]; } byte[] t4 = new byte[20]; sha.update(account.getName().toUpperCase().getBytes(Charset.forName("UTF-8"))); t4 = sha.digest(); sha.update(hash); sha.update(t4); sha.update(account.getS_crypto().asByteArray(32)); sha.update(A.asByteArray(32)); sha.update(B.asByteArray(32)); sha.update(vK); final byte[] sh = sha.digest(); if (Arrays.equals(sh, m1)) { sha.update(A.asByteArray(32)); sha.update(sh); sha.update(vK); account.setM2(sha.digest()); account.setvK(vK); ArrayUtils.reverse(vK); final AccountEntity accountEntity = this.accountService.readAccountByUserName(account.getName()); if (accountEntity != null) { final String sessionKey = new BigInteger(1, vK).toString(16).toUpperCase(); accountEntity.setSessionKey(sessionKey); account.setSessionKey(new BigNumber(vK)); this.accountService.createOrUpdateAccount(accountEntity); } else { return WoWAuthResponse.WOW_FAIL_INCORRECT_PASSWORD; } return WoWAuthResponse.WOW_SUCCESS; } else { return WoWAuthResponse.WOW_FAIL_INCORRECT_PASSWORD; } } public boolean checkSessionKey(final AccountInfo account, final byte[] R1, final byte[] R2) { MessageDigest sha = null; try { sha = MessageDigest.getInstance("SHA-1"); } catch (final NoSuchAlgorithmException e) { e.printStackTrace(); return false; } final AccountEntity accountEntity = this.accountService.readAccountByUserName(account.getName()); if (accountEntity != null) { final String sessionKey = accountEntity.getSessionKey(); sha.update(account.getName().getBytes(Charset.forName("UTF-8"))); sha.update(R1); sha.update(account.get_reconnectProof().asByteArray(16)); sha.update(convertSessionKey(sessionKey)); } else { return false; } if (Arrays.equals(sha.digest(), R2)) { return true; } else { return false; } } public AccountInfo getAccount(final String login) { // final Criterion criterion = Restrictions.eq("username", login); final AccountEntity account = this.accountService.readAccountByUserName(login); if (account != null) { final AccountInfo accountInfo = new AccountInfo(); accountInfo.setObjectId(account.getId()); accountInfo.setName(account.getUsername()); accountInfo.setSessionKey(new BigNumber(account.getSessionKey())); return accountInfo; } return null; } /** * Convert to session key. * * @param hexkey * * @return the byte[] */ private byte[] convertSessionKey(final String hexkey) { final int len = hexkey.length(); final byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[((len - i) / 2) - 1] = (byte) ((Character.digit(hexkey.charAt(i), 16) << 4) + Character.digit(hexkey.charAt(i + 1), 16)); } return data; } /** * Load clean. * * @param name * the name * @param channelHandler * the channel handler */ public void loadClean(final String name, final NettyNetworkChannel channelHandler) { final AccountInfo account = this.accounts.getNamedObject(name); channelHandler.setChanneledObject(account); } /** * Find and clean account in Account container. * * @param accountName * - account's name. * @return AccountInfo - relation to accountName. */ public AccountInfo getAndCleanAccount(final String accountName) { final AccountInfo aInfo = this.accounts.getNamedObject(accountName); if (aInfo != null) { this.accounts.removeObject(aInfo); } return aInfo; } }