chickenbutt Posted November 27, 2011 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); } }
chickenbutt Posted December 1, 2011 Author 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.
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