chickenbutt Posted November 27, 2011 Share Posted November 27, 2011 Was messing around in Java and wrote this up. Improvements?public final class KeyDecoder{ private static int CalculateHash(String licenseName) { int hash = 0; for (int i = 0; i < licenseName.length(); i++) { int xorValue = licenseName.charAt(i); int rotateSequence = xorValue; for (int j = 0; j < 4; j++) { int rotateLeft = rotateSequence & 0x3; int shiftLeft = rotateLeft; int shiftRight = 32 - rotateLeft; int rotatedBits = hash >>> shiftRight; hash = hash << shiftLeft | rotatedBits; hash ^= xorValue; rotateSequence >>= 2; } } return hash + 1 & 0xFFFF; } public static short[] getInfoArray(String registrationName, String registrationCode) { short[] infoArray = (short[])null; if ((registrationName != null) && (registrationCode != null)) { registrationName = registrationName.toUpperCase().trim(); registrationCode = registrationCode.toUpperCase().trim(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < registrationCode.length(); i++) { char ch = registrationCode.charAt(i); if (!Character.isLetter(ch)) { continue; } sb.append(ch); } registrationCode = sb.toString(); int registrationCodeLen = registrationCode.length(); if ((registrationName.length() > 0) && (registrationCodeLen > 0)) { Vector dataWordList = new Vector(); int checksum = 0; int offset = 0; int chCode = 65; while (offset < registrationCodeLen) { int dataWord = 0; for (int i = 0; i < 4; i++) { if (offset >= registrationCodeLen) continue; int ch = registrationCode.charAt(offset++); int chDiff = ch >= chCode ? ch - chCode : ch + 26 - chCode; dataWord = dataWord << 4 | chDiff - 1; chCode = ch; } checksum += dataWord; dataWordList.add(new Integer(dataWord)); } Integer HashCode = (Integer)dataWordList.get(1); Integer CheckSum = (Integer)dataWordList.get(dataWordList.size() - 1); int tCheckSum = CheckSum.intValue(); if ((checksum - tCheckSum & 0xFFFF) == tCheckSum) { int tHashCode = HashCode.intValue(); if (tHashCode == CalculateHash(registrationName)) { int nitems = dataWordList.size() - 3; if (nitems > 0) { Integer dataWord = (Integer)dataWordList.get(0); int randomNumber = dataWord.intValue() & 0xFFFF; infoArray = new short[nitems]; for (int i = 0; i < nitems; i++) { dataWord = (Integer)dataWordList.get(2 + i); infoArray[i] = (short)((dataWord.intValue() ^ randomNumber) & 0xFFFF); } } } } } } return infoArray; } public static boolean getInfoArray(String registrationName, String registrationCode, short[] infoArray) { int[] dataWordList = (int[])null; int numDataWords = 0; int checksum = 0; boolean validFlag = true; if ((registrationName != null) && (registrationCode != null)) { registrationName = registrationName.toUpperCase().trim(); registrationCode = registrationCode.toUpperCase().trim(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < registrationCode.length(); i++) { char ch = registrationCode.charAt(i); if ((ch < 'A') || (ch > 'Z')) continue; sb.append(ch); } registrationCode = sb.toString(); } else { validFlag = false; } if (validFlag) { int registrationCodeLen = registrationCode.length(); if ((registrationName.length() > 0) && (registrationCodeLen > 0)) { dataWordList = new int[infoArray.length + 3]; int offset = 0; int chCode = 65; while (offset < registrationCodeLen) { int dataWord = 0; for (int i = 0; i < 4; i++) { if (offset >= registrationCodeLen) continue; int ch = registrationCode.charAt(offset++); int chDiff = ch >= chCode ? ch - chCode : ch + 26 - chCode; dataWord = dataWord << 4 | chDiff - 1; chCode = ch; } checksum += dataWord; if (numDataWords < dataWordList.length) dataWordList[(numDataWords++)] = dataWord; else validFlag = false; } } else { validFlag = false; } } if (validFlag) { int tCheckSum = dataWordList[(numDataWords - 1)]; if ((checksum - tCheckSum & 0xFFFF) == tCheckSum) { int tHashCode = dataWordList[1]; if (tHashCode == CalculateHash(registrationName)) { int nitems = numDataWords - 3; if (nitems > 0) { int randomNumber = dataWordList[0] & 0xFFFF; for (int i = 0; i < nitems; i++) { int dataWord = dataWordList[(2 + i)]; infoArray[i] = (short)((dataWord ^ randomNumber) & 0xFFFF); } } else { validFlag = false; } } else { validFlag = false; } } else { validFlag = false; } } return validFlag; }}public final class KeyDecoder{ private static int CalculateHash(String licenseName) { int hash = 0; for (int i = 0; i < licenseName.length(); i++) { int xorValue = licenseName.charAt(i); int rotateSequence = xorValue; for (int j = 0; j < 4; j++) { int rotateLeft = rotateSequence & 0x3; int shiftLeft = rotateLeft; int shiftRight = 32 - rotateLeft; int rotatedBits = hash >>> shiftRight; hash = hash << shiftLeft | rotatedBits; hash ^= xorValue; rotateSequence >>= 2; } } return hash + 1 & 0xFFFF; } public static short[] getInfoArray(String registrationName, String registrationCode) { short[] infoArray = (short[])null; if ((registrationName != null) && (registrationCode != null)) { registrationName = registrationName.toUpperCase().trim(); registrationCode = registrationCode.toUpperCase().trim(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < registrationCode.length(); i++) { char ch = registrationCode.charAt(i); if (!Character.isLetter(ch)) { continue; } sb.append(ch); } registrationCode = sb.toString(); int registrationCodeLen = registrationCode.length(); if ((registrationName.length() > 0) && (registrationCodeLen > 0)) { Vector dataWordList = new Vector(); int checksum = 0; int offset = 0; int chCode = 65; while (offset < registrationCodeLen) { int dataWord = 0; for (int i = 0; i < 4; i++) { if (offset >= registrationCodeLen) continue; int ch = registrationCode.charAt(offset++); int chDiff = ch >= chCode ? ch - chCode : ch + 26 - chCode; dataWord = dataWord << 4 | chDiff - 1; chCode = ch; } checksum += dataWord; dataWordList.add(new Integer(dataWord)); } Integer HashCode = (Integer)dataWordList.get(1); Integer CheckSum = (Integer)dataWordList.get(dataWordList.size() - 1); int tCheckSum = CheckSum.intValue(); if ((checksum - tCheckSum & 0xFFFF) == tCheckSum) { int tHashCode = HashCode.intValue(); if (tHashCode == CalculateHash(registrationName)) { int nitems = dataWordList.size() - 3; if (nitems > 0) { Integer dataWord = (Integer)dataWordList.get(0); int randomNumber = dataWord.intValue() & 0xFFFF; infoArray = new short[nitems]; for (int i = 0; i < nitems; i++) { dataWord = (Integer)dataWordList.get(2 + i); infoArray[i] = (short)((dataWord.intValue() ^ randomNumber) & 0xFFFF); } } } } } } return infoArray; } public static boolean getInfoArray(String registrationName, String registrationCode, short[] infoArray) { int[] dataWordList = (int[])null; int numDataWords = 0; int checksum = 0; boolean validFlag = true; if ((registrationName != null) && (registrationCode != null)) { registrationName = registrationName.toUpperCase().trim(); registrationCode = registrationCode.toUpperCase().trim(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < registrationCode.length(); i++) { char ch = registrationCode.charAt(i); if ((ch < 'A') || (ch > 'Z')) continue; sb.append(ch); } registrationCode = sb.toString(); } else { validFlag = false; } if (validFlag) { int registrationCodeLen = registrationCode.length(); if ((registrationName.length() > 0) && (registrationCodeLen > 0)) { dataWordList = new int[infoArray.length + 3]; int offset = 0; int chCode = 65; while (offset < registrationCodeLen) { int dataWord = 0; for (int i = 0; i < 4; i++) { if (offset >= registrationCodeLen) continue; int ch = registrationCode.charAt(offset++); int chDiff = ch >= chCode ? ch - chCode : ch + 26 - chCode; dataWord = dataWord << 4 | chDiff - 1; chCode = ch; } checksum += dataWord; if (numDataWords < dataWordList.length) dataWordList[(numDataWords++)] = dataWord; else validFlag = false; } } else { validFlag = false; } } if (validFlag) { int tCheckSum = dataWordList[(numDataWords - 1)]; if ((checksum - tCheckSum & 0xFFFF) == tCheckSum) { int tHashCode = dataWordList[1]; if (tHashCode == CalculateHash(registrationName)) { int nitems = numDataWords - 3; if (nitems > 0) { int randomNumber = dataWordList[0] & 0xFFFF; for (int i = 0; i < nitems; i++) { int dataWord = dataWordList[(2 + i)]; infoArray[i] = (short)((dataWord ^ randomNumber) & 0xFFFF); } } else { validFlag = false; } } else { validFlag = false; } } else { validFlag = false; } } return validFlag; }} private void CheckRegistered() { int todaysDate = (int)(System.currentTimeMillis() / 86400000L); aboutMessage = null; if ((username != null) && (username.length() > 0)) { if ((registrationCode != null) && (registrationCode.length() > 0)) { short[] infoArray = new short[2]; if (KeyDecoder.getInfoArray(username, registrationCode, infoArray)) { expiryDate = infoArray[0]; iEdition = infoArray[1]; if ((iEdition >= 0) && (iEdition <= 2)) { boolean keyValid = true; expiryDate = infoArray[0]; if (expiryDate > 0) { if (expiryDate >= 15286) { registeredFlag = true; } else { Date date = new Date(expiryDate * 24L * 60L * 60L * 1000L); Calendar cal = Calendar.getInstance(); cal.setTime(date); int ccyy = cal.get(1); int month = cal.get(2); int day = cal.get(5); registerMessage = String.format("Registration code not valid for Product released after %d/%d/%4d", new Object[] { Integer.valueOf(day), Integer.valueOf(month), Integer.valueOf(ccyy) }); registeredFlag = false; } } else if (expiryDate < 0) { if (todaysDate <= -expiryDate) { registeredFlag = true; } else { Date date = new Date(-expiryDate * 24L * 60L * 60L * 1000L); Calendar cal = Calendar.getInstance(); cal.setTime(date); int ccyy = cal.get(1); int month = cal.get(2); int day = cal.get(5); registerMessage = String.format("Registration code expired on %d/%d/%4d", new Object[] { Integer.valueOf(day), Integer.valueOf(month), Integer.valueOf(ccyy) }); registeredFlag = false; } } else { registerMessage = "Registration code has expired"; registeredFlag = false; } } else { boolean keyValid = false; registerMessage = "Registration code is not valid for this product"; registeredFlag = false; } } else { registerMessage = "*** Invalid Key ***"; registeredFlag = false; } } else { registerMessage = "Missing registration code"; registeredFlag = false; } } else { registerMessage = "Missing username"; registeredFlag = false; } if (registeredFlag) { switch (iEdition) { case -1: setTitle(version + " (Unregistered Edition)"); break; case 0: setTitle(version + " (Personal Edition)"); break; case 1: setTitle(version + " (Business Edition)"); break; case 2: setTitle(version + " (GameCreators Edition)"); break; default: setTitle(version + " (Unknown Edition)"); } this.registerMenuItem.setVisible(false); this.registerMenuItem.setVisible(true); } else { setTitle(version + " - Trial Version"); this.registerMenuItem.setVisible(true); } } Link to comment
Killboy Posted November 27, 2011 Share Posted November 27, 2011 Anything not working as expected? Link to comment
chickenbutt Posted December 1, 2011 Author Share Posted December 1, 2011 Anything not working as expected?no. It's actually weak, the hashing function is just a shift+decode function, and the rest just converts underlying segments into date and edition info.If I was doing a serious one it'd be export friendly RSA off of a HWID that go to a one-time server check which returns a key file that is sent through some RSA+HWID based decryption routines on-load, all under a good control-flow+crypt protector. I think JVM actually has a DRM API, or at least J2ME does I think, that has crypto and some isolation. Isolation is the key though, unfortunatly x86 has none that isn't accessble through debug+trace, except on newer Intel which is only accessible to rich vendors, and I think has been defeated. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now