Serial keys: What to do? - java
I've been reading some posts here and articles around the web but I can't picture a serial keys based system for my application.
http://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi/
I read this one but I can't turn the code into Java and I'm not very familiar with the terms either.
What possible insight can you give me on this? Ideally my application will be for sale but I don't expect it to be much popular, I don't mind much if it gets cracked if I have users that appreciate the product and buy it, but I want to avoid it to be easily cracked. Please be as specific as you can, I'm somewhat new to Java.
Thanks in advance.
I was quite interested in that article, so I implemented the code in Java. may be of use
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
public class KeyValidator {
private static final byte[][] params = new byte[][] { { 24, 4, 127 }, { 10, 0, 56 }, { 1, 2, 91 }, { 7, 1, 100 } };
private static final Set<String> blacklist = new TreeSet<String>();
static {
blacklist.add("11111111");
}
private static byte PKV_GetKeyByte(final int seed, final byte a, final byte b, final byte c) {
final int a1 = a % 25;
final int b1 = b % 3;
if (a1 % 2 == 0) {
return (byte) (((seed >> a1) & 0x000000FF) ^ ((seed >> b1) | c));
} else {
return (byte) (((seed >> a1) & 0x000000FF) ^ ((seed >> b1) & c));
}
}
private static String PKV_GetChecksum(final String s) {
int left = 0x0056;
int right = 0x00AF;
for (byte b : s.getBytes()) {
right += b;
if (right > 0x00FF) {
right -= 0x00FF;
}
left += right;
if (left > 0x00FF) {
left -= 0x00FF;
}
}
int sum = (left << 8) + right;
return intToHex(sum, 4);
}
public static String PKV_MakeKey(final int seed) {
// Fill KeyBytes with values derived from Seed.
// The parameters used here must be exactly the same
// as the ones used in the PKV_CheckKey function.
// A real key system should use more than four bytes.
final byte[] keyBytes = new byte[4];
keyBytes[0] = PKV_GetKeyByte(seed, params[0][0], params[0][1], params[0][2]);
keyBytes[1] = PKV_GetKeyByte(seed, params[1][0], params[1][1], params[1][2]);
keyBytes[2] = PKV_GetKeyByte(seed, params[2][0], params[2][1], params[2][2]);
keyBytes[3] = PKV_GetKeyByte(seed, params[3][0], params[3][1], params[3][2]);
// the key string begins with a hexadecimal string of the seed
final StringBuilder result = new StringBuilder(intToHex(seed, 8));
// then is followed by hexadecimal strings of each byte in the key
for (byte b : keyBytes) {
result.append(intToHex(b, 2));
}
// add checksum to key string
result.append(PKV_GetChecksum(result.toString()));
final String key = result.toString();
return key.substring(0, 4) + "-" + key.substring(4, 8) + "-" + key.substring(8, 12) + "-" + key.substring(12, 16) + "-" + key.substring(16, 20);
}
private static boolean PKV_CheckKeyChecksum(final String key) {
// remove cosmetic hyphens and normalise case
final String comp = key.replaceAll("-", "").toLowerCase(Locale.UK);
if (comp.length() != 20) {
return false; // Our keys are always 20 characters long
}
// last four characters are the checksum
final String checksum = comp.substring(16);
return checksum.equals(PKV_GetChecksum(comp.substring(0, 16)));
}
public static Status PKV_CheckKey(final String key) {
if (!PKV_CheckKeyChecksum(key)) {
return Status.KEY_INVALID; // bad checksum or wrong number of
// characters
}
// remove cosmetic hyphens and normalise case
final String comp = key.replaceAll("-", "").toLowerCase(Locale.UK);
// test against blacklist
for (String bl : blacklist) {
if (comp.startsWith(bl)) {
return Status.KEY_BLACKLISTED;
}
}
// At this point, the key is either valid or forged,
// because a forged key can have a valid checksum.
// We now test the "bytes" of the key to determine if it is
// actually valid.
// When building your release application, use conditional defines
// or comment out most of the byte checks! This is the heart
// of the partial key verification system. By not compiling in
// each check, there is no way for someone to build a keygen that
// will produce valid keys. If an invalid keygen is released, you
// simply change which byte checks are compiled in, and any serial
// number built with the fake keygen no longer works.
// Note that the parameters used for PKV_GetKeyByte calls MUST
// MATCH the values that PKV_MakeKey uses to make the key in the
// first place!
// extract the Seed from the supplied key string
final int seed;
try {
seed = Integer.valueOf(comp.substring(0, 8), 16);
} catch (NumberFormatException e) {
return Status.KEY_PHONY;
}
// test key 0
final String kb0 = comp.substring(8, 10);
final byte b0 = PKV_GetKeyByte(seed, params[0][0], params[0][1], params[0][2]);
if (!kb0.equals(intToHex(b0, 2))) {
return Status.KEY_PHONY;
}
// test key1
final String kb1 = comp.substring(10, 12);
final byte b1 = PKV_GetKeyByte(seed, params[1][0], params[1][1], params[1][2]);
if (!kb1.equals(intToHex(b1, 2))) {
return Status.KEY_PHONY;
}
// test key2
final String kb2 = comp.substring(12, 14);
final byte b2 = PKV_GetKeyByte(seed, params[2][0], params[2][1], params[2][2]);
if (!kb2.equals(intToHex(b2, 2))) {
return Status.KEY_PHONY;
}
// test key3
final String kb3 = comp.substring(14, 16);
final byte b3 = PKV_GetKeyByte(seed, params[3][0], params[3][1], params[3][2]);
if (!kb3.equals(intToHex(b3, 2))) {
return Status.KEY_PHONY;
}
// If we get this far, then it means the key is either good, or was made
// with a keygen derived from "this" release.
return Status.KEY_GOOD;
}
protected static String intToHex(final Number n, final int chars) {
return String.format("%0" + chars + "x", n);
}
public enum Status {
KEY_GOOD, KEY_INVALID, KEY_BLACKLISTED, KEY_PHONY
}
}
It's not that hard, if you're somewhat flexible in your requirements -- perhaps the scheme below would work for you.
You could just produce K = [SN, H([X,SN,Y])] which is the concatenation of an incrementing serial number with a hash, where the hash is a secure hash function of the concatenation of the serial number between unique constants X and Y that are secret "salt" you use to prevent the use of rainbow tables.
Use a well-known secure hash algorithm (e.g. SHA-1 or SHA-2; MD5 is probably also adequate, since the known weaknesses for MD5 are collision attacks, and not preimage attacks) and you should be all set, as least as far as the serial key part goes (you'll probably want to prevent two people from using the same key).
The other thing you can do which is helpful is use K = [SN, T, H([X, SN, T, Y])] -- use both the serial number and a timestamp. This can be used to allow only a narrow use window for the serial key: it's valid within N seconds of the timestamp, so it would prevent reuse of the key outside that window.
Then encode/decode K to a representation that can be used to easily allow users to enter the key (e.g. base64).
It's best to have a simple and transparent overall algorithm -- obfuscation is not going to help you if someone reverse-engineers your scheme.
Securing applications in general isn't a simple task. A lot of companies are investing a lot of money to find new securing algorithms, which get all cracked very fast.
Securing Java applications is a bit more difficult. Any serial verification algorithm embedded within your application can be decompiled, so a serial key generator will be pretty easy to build.
A good starting point is the article you gave. It tells you how to build a key verification system, and how to generate keys for your (legitimate) users.
After implementing such an algorithm, I'd suggest you to secure the source code a little, so decompilation become a little more "tricky". Use code obfuscation techniques to hide your verification algorithm implementation. This will also make the task harder for people trying to crack your application just by modifying byte-code.
A good technique could be to export your key verification algorithm on a remote server. The client send the key to the server, which replies with a 'validation code' to tell your application that your key is valid. But this doesn't prevents users from modifying your application to remove any key verification procedure. And this might be very annoying for legitimate users who don't have a 24-hours Internet connection. I'm thinking about Steam, which verify the key validity at every launch on Internet, and which annoys a lot of users.
To find a good protection technique, look around you and try to determine how others people do, which techniques are working, which aren't. They are a lot of example (Video game industry, in particular). But keep in mind that even the best companies aren't able to secure their applications correctly. No techniques are unbreakable.
Related
What is exactly done here? Trying to transfer code from Java to NodeJS
I'm currently trying to move over some encoding script from Java to NodeJs. At the moment the current Java script is as follows: public static final char[] chars = "0123456789abcdef".toCharArray(); public static String sha1Digest(String str) { try { MessageDigest instance = MessageDigest.getInstance('SHA-1'); instance.reset(); instance.update(str.getBytes('UTF-8')); return lastEncode(instance.digest()); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } public static String lastEncode(byte[] bArr) { StringBuilder encoded = new StringBuilder(bArr.length * 2); for (byte b : bArr) { encoded.append(chars[(b >> 4) & 15]); encoded.append(chars[b & 15]); } return encoded.toString(); } The initial parameter passed to the sha1Digest function is a string that consists of a URL appended with a secret key. Currently, I'm trying to transfer the code over to NodeJs in which I have this code (for now): async function sha1Digest(str) { try { const sha1 = crypto.createHmac("SHA1"); const hmac = sha1.update(new Buffer(str, 'utf-8')); return encoder(hmac.digest()); } catch (e) { console.dir(e); } } async function lastEncode(bArr) { let chars = "0123456789abcdef".split('') let sb = ''; for (b in bArr) { sb = sb + (chars[(b >> 4) & 15]); sb = sb + (chars[b & 15]); } return sb; } Sadly tho, I have no understanding of what the part in the for loop in lastEncode does. Is anybody able to help me out with this, and also verify that the sha1Digest function seems correct in the NodeJS? Much appreciated!
lastEncode turns a byte array into hex nibbles. It turns the array: new byte[] {10, 16, (byte) 255} into the string "0a10ff". (0a is hex notation for 10, ff is hex notation for 255, etc - if this sounds like gobbledygook to you, the web has many tutorials on hexadecimal :P). Your javascript translation messes up because you're joining on ,. More generally, to do that 'bytes to nibbles' operation of before, see this SO answer. Just test the lastEncode function by itself. Run it in java, then run your javascript port, and ensure the exact same string is produced in both variants. Only then, move on to the hashing part. NB: To be clear, this protocol is rather idiotic - you can just hash the byte array itself, there is no need to waste a ton of time turning that into hex nibbles (which is always exactly 2x as large as the input) and then hashing that. But, presumably, you can't mess with the protocol at this point. But if you can, change it. It'll be faster, simpler to explain, and less code. Win-win-win. EDIT: NB: You also are using a different hash algorithm in the javascript side (HMAC-SHA1 is not the same as just SHA1).
Trying to assign a random ID to an object [duplicate]
I've been looking for a simple Java algorithm to generate a pseudo-random alpha-numeric string. In my situation it would be used as a unique session/key identifier that would "likely" be unique over 500K+ generation (my needs don't really require anything much more sophisticated). Ideally, I would be able to specify a length depending on my uniqueness needs. For example, a generated string of length 12 might look something like "AEYGF7K0DM1X".
Algorithm To generate a random string, concatenate characters drawn randomly from the set of acceptable symbols until the string reaches the desired length. Implementation Here's some fairly simple and very flexible code for generating random identifiers. Read the information that follows for important application notes. public class RandomString { /** * Generate a random string. */ public String nextString() { for (int idx = 0; idx < buf.length; ++idx) buf[idx] = symbols[random.nextInt(symbols.length)]; return new String(buf); } public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; public static final String lower = upper.toLowerCase(Locale.ROOT); public static final String digits = "0123456789"; public static final String alphanum = upper + lower + digits; private final Random random; private final char[] symbols; private final char[] buf; public RandomString(int length, Random random, String symbols) { if (length < 1) throw new IllegalArgumentException(); if (symbols.length() < 2) throw new IllegalArgumentException(); this.random = Objects.requireNonNull(random); this.symbols = symbols.toCharArray(); this.buf = new char[length]; } /** * Create an alphanumeric string generator. */ public RandomString(int length, Random random) { this(length, random, alphanum); } /** * Create an alphanumeric strings from a secure generator. */ public RandomString(int length) { this(length, new SecureRandom()); } /** * Create session identifiers. */ public RandomString() { this(21); } } Usage examples Create an insecure generator for 8-character identifiers: RandomString gen = new RandomString(8, ThreadLocalRandom.current()); Create a secure generator for session identifiers: RandomString session = new RandomString(); Create a generator with easy-to-read codes for printing. The strings are longer than full alphanumeric strings to compensate for using fewer symbols: String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx"; RandomString tickets = new RandomString(23, new SecureRandom(), easy); Use as session identifiers Generating session identifiers that are likely to be unique is not good enough, or you could just use a simple counter. Attackers hijack sessions when predictable identifiers are used. There is tension between length and security. Shorter identifiers are easier to guess, because there are fewer possibilities. But longer identifiers consume more storage and bandwidth. A larger set of symbols helps, but might cause encoding problems if identifiers are included in URLs or re-entered by hand. The underlying source of randomness, or entropy, for session identifiers should come from a random number generator designed for cryptography. However, initializing these generators can sometimes be computationally expensive or slow, so effort should be made to re-use them when possible. Use as object identifiers Not every application requires security. Random assignment can be an efficient way for multiple entities to generate identifiers in a shared space without any coordination or partitioning. Coordination can be slow, especially in a clustered or distributed environment, and splitting up a space causes problems when entities end up with shares that are too small or too big. Identifiers generated without taking measures to make them unpredictable should be protected by other means if an attacker might be able to view and manipulate them, as happens in most web applications. There should be a separate authorization system that protects objects whose identifier can be guessed by an attacker without access permission. Care must be also be taken to use identifiers that are long enough to make collisions unlikely given the anticipated total number of identifiers. This is referred to as "the birthday paradox." The probability of a collision, p, is approximately n2/(2qx), where n is the number of identifiers actually generated, q is the number of distinct symbols in the alphabet, and x is the length of the identifiers. This should be a very small number, like 2β50 or less. Working this out shows that the chance of collision among 500k 15-character identifiers is about 2β52, which is probably less likely than undetected errors from cosmic rays, etc. Comparison with UUIDs According to their specification, UUIDs are not designed to be unpredictable, and should not be used as session identifiers. UUIDs in their standard format take a lot of space: 36 characters for only 122 bits of entropy. (Not all bits of a "random" UUID are selected randomly.) A randomly chosen alphanumeric string packs more entropy in just 21 characters. UUIDs are not flexible; they have a standardized structure and layout. This is their chief virtue as well as their main weakness. When collaborating with an outside party, the standardization offered by UUIDs may be helpful. For purely internal use, they can be inefficient.
Java supplies a way of doing this directly. If you don't want the dashes, they are easy to strip out. Just use uuid.replace("-", "") import java.util.UUID; public class randomStringGenerator { public static void main(String[] args) { System.out.println(generateString()); } public static String generateString() { String uuid = UUID.randomUUID().toString(); return "uuid = " + uuid; } } Output uuid = 2d7428a6-b58c-4008-8575-f05549f16316
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static SecureRandom rnd = new SecureRandom(); String randomString(int len){ StringBuilder sb = new StringBuilder(len); for(int i = 0; i < len; i++) sb.append(AB.charAt(rnd.nextInt(AB.length()))); return sb.toString(); }
If you're happy to use Apache classes, you could use org.apache.commons.text.RandomStringGenerator (Apache Commons Text). Example: RandomStringGenerator randomStringGenerator = new RandomStringGenerator.Builder() .withinRange('0', 'z') .filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS) .build(); randomStringGenerator.generate(12); // toUpperCase() if you want Since Apache Commons Lang 3.6, RandomStringUtils is deprecated.
You can use an Apache Commons library for this, RandomStringUtils: RandomStringUtils.randomAlphanumeric(20).toUpperCase();
In one line: Long.toHexString(Double.doubleToLongBits(Math.random())); Source: Java - generating a random string
This is easily achievable without any external libraries. 1. Cryptographic Pseudo Random Data Generation (PRNG) First you need a cryptographic PRNG. Java has SecureRandom for that and typically uses the best entropy source on the machine (e.g. /dev/random). Read more here. SecureRandom rnd = new SecureRandom(); byte[] token = new byte[byteLength]; rnd.nextBytes(token); Note: SecureRandom is the slowest, but most secure way in Java of generating random bytes. I do however recommend not considering performance here since it usually has no real impact on your application unless you have to generate millions of tokens per second. 2. Required Space of Possible Values Next you have to decide "how unique" your token needs to be. The whole and only point of considering entropy is to make sure that the system can resist brute force attacks: the space of possible values must be so large that any attacker could only try a negligible proportion of the values in non-ludicrous time1. Unique identifiers such as random UUID have 122 bit of entropy (i.e., 2^122 = 5.3x10^36) - the chance of collision is "*(...) for there to be a one in a billion chance of duplication, 103 trillion version 4 UUIDs must be generated2". We will choose 128 bits since it fits exactly into 16 bytes and is seen as highly sufficient for being unique for basically every, but the most extreme, use cases and you don't have to think about duplicates. Here is a simple comparison table of entropy including simple analysis of the birthday problem. For simple requirements, 8 or 12 byte length might suffice, but with 16 bytes you are on the "safe side". And that's basically it. The last thing is to think about encoding so it can be represented as a printable text (read, a String). 3. Binary to Text Encoding Typical encodings include: Base64 every character encodes 6 bit, creating a 33% overhead. Fortunately there are standard implementations in Java 8+ and Android. With older Java you can use any of the numerous third-party libraries. If you want your tokens to be URL safe use the URL-safe version of RFC4648 (which usually is supported by most implementations). Example encoding 16 bytes with padding: XfJhfv3C0P6ag7y9VQxSbw== Base32 every character encodes 5 bit, creating a 40% overhead. This will use A-Z and 2-7, making it reasonably space efficient while being case-insensitive alpha-numeric. There isn't any standard implementation in the JDK. Example encoding 16 bytes without padding: WUPIL5DQTZGMF4D3NX5L7LNFOY Base16 (hexadecimal) every character encodes four bit, requiring two characters per byte (i.e., 16 bytes create a string of length 32). Therefore hexadecimal is less space efficient than Base32, but it is safe to use in most cases (URL) since it only uses 0-9 and A to F. Example encoding 16 bytes: 4fa3dd0f57cb3bf331441ed285b27735. See a StackΒ Overflow discussion about converting to hexadecimal here. Additional encodings like Base85 and the exotic Base122 exist with better/worse space efficiency. You can create your own encoding (which basically most answers in this thread do), but I would advise against it, if you don't have very specific requirements. See more encoding schemes in the Wikipedia article. 4. Summary and Example Use SecureRandom Use at least 16 bytes (2^128) of possible values Encode according to your requirements (usually hex or base32 if you need it to be alpha-numeric) Don't ... use your home brew encoding: better maintainable and readable for others if they see what standard encoding you use instead of weird for loops creating characters at a time. ... use UUID: it has no guarantees on randomness; you are wasting 6 bits of entropy and have a verbose string representation Example: Hexadecimal Token Generator public static String generateRandomHexToken(int byteLength) { SecureRandom secureRandom = new SecureRandom(); byte[] token = new byte[byteLength]; secureRandom.nextBytes(token); return new BigInteger(1, token).toString(16); // Hexadecimal encoding } //generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd Example: Base64 Token Generator (URL Safe) public static String generateRandomBase64Token(int byteLength) { SecureRandom secureRandom = new SecureRandom(); byte[] token = new byte[byteLength]; secureRandom.nextBytes(token); return Base64.getUrlEncoder().withoutPadding().encodeToString(token); //base64 encoding } //generateRandomBase64Token(16) -> EEcCCAYuUcQk7IuzdaPzrg Example: Java CLI Tool If you want a ready-to-use CLI tool you may use dice: Example: Related issue - Protect Your Current Ids If you already have an id you can use (e.g., a synthetic long in your entity), but don't want to publish the internal value, you can use this library to encrypt it and obfuscate it: https://github.com/patrickfav/id-mask IdMask<Long> idMask = IdMasks.forLongIds(Config.builder(key).build()); String maskedId = idMask.mask(id); // Example: NPSBolhMyabUBdTyanrbqT8 long originalId = idMask.unmask(maskedId);
Using Dollar should be as simple as: // "0123456789" + "ABCDE...Z" String validCharacters = $('0', '9').join() + $('A', 'Z').join(); String randomString(int length) { return $(validCharacters).shuffle().slice(length).toString(); } #Test public void buildFiveRandomStrings() { for (int i : $(5)) { System.out.println(randomString(12)); } } It outputs something like this: DKL1SBH9UJWC JH7P0IT21EA5 5DTI72EO6SFU HQUMJTEBNF7Y 1HCR6SKYWGT7
Here it is in Java: import static java.lang.Math.round; import static java.lang.Math.random; import static java.lang.Math.pow; import static java.lang.Math.abs; import static java.lang.Math.min; import static org.apache.commons.lang.StringUtils.leftPad public class RandomAlphaNum { public static String gen(int length) { StringBuffer sb = new StringBuffer(); for (int i = length; i > 0; i -= 12) { int n = min(12, abs(i)); sb.append(leftPad(Long.toString(round(random() * pow(36, n)), 36), n, '0')); } return sb.toString(); } } Here's a sample run: scala> RandomAlphaNum.gen(42) res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy
A short and easy solution, but it uses only lowercase and numerics: Random r = new java.util.Random (); String s = Long.toString (r.nextLong () & Long.MAX_VALUE, 36); The size is about 12 digits to base 36 and can't be improved further, that way. Of course you can append multiple instances.
Surprising, no one here has suggested it, but: import java.util.UUID UUID.randomUUID().toString(); Easy. The benefit of this is UUIDs are nice, long, and guaranteed to be almost impossible to collide. Wikipedia has a good explanation of it: " ...only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%." The first four bits are the version type and two for the variant, so you get 122 bits of random. So if you want to, you can truncate from the end to reduce the size of the UUID. It's not recommended, but you still have loads of randomness, enough for your 500k records easy.
An alternative in Java 8 is: static final Random random = new Random(); // Or SecureRandom static final int startChar = (int) '!'; static final int endChar = (int) '~'; static String randomString(final int maxLength) { final int length = random.nextInt(maxLength + 1); return random.ints(length, startChar, endChar + 1) .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) .toString(); }
public static String generateSessionKey(int length){ String alphabet = new String("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); // 9 int n = alphabet.length(); // 10 String result = new String(); Random r = new Random(); // 11 for (int i=0; i<length; i++) // 12 result = result + alphabet.charAt(r.nextInt(n)); //13 return result; }
import java.util.Random; public class passGen{ // Version 1.0 private static final String dCase = "abcdefghijklmnopqrstuvwxyz"; private static final String uCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String sChar = "!##$%^&*"; private static final String intChar = "0123456789"; private static Random r = new Random(); private static StringBuilder pass = new StringBuilder(); public static void main (String[] args) { System.out.println ("Generating pass..."); while (pass.length () != 16){ int rPick = r.nextInt(4); if (rPick == 0){ int spot = r.nextInt(26); pass.append(dCase.charAt(spot)); } else if (rPick == 1) { int spot = r.nextInt(26); pass.append(uCase.charAt(spot)); } else if (rPick == 2) { int spot = r.nextInt(8); pass.append(sChar.charAt(spot)); } else { int spot = r.nextInt(10); pass.append(intChar.charAt(spot)); } } System.out.println ("Generated Pass: " + pass.toString()); } } This just adds the password into the string and... yeah, it works well. Check it out... It is very simple; I wrote it.
Using UUIDs is insecure, because parts of the UUID aren't random at all. The procedure of erickson is very neat, but it does not create strings of the same length. The following snippet should be sufficient: /* * The random generator used by this class to create random keys. * In a holder class to defer initialization until needed. */ private static class RandomHolder { static final Random random = new SecureRandom(); public static String randomKey(int length) { return String.format("%"+length+"s", new BigInteger(length*5/*base 32,2^5*/, random) .toString(32)).replace('\u0020', '0'); } } Why choose length*5? Let's assume the simple case of a random string of length 1, so one random character. To get a random character containing all digits 0-9 and characters a-z, we would need a random number between 0 and 35 to get one of each character. BigInteger provides a constructor to generate a random number, uniformly distributed over the range 0 to (2^numBits - 1). Unfortunately 35 is not a number which can be received by 2^numBits - 1. So we have two options: Either go with 2^5-1=31 or 2^6-1=63. If we would choose 2^6 we would get a lot of "unnecessary" / "longer" numbers. Therefore 2^5 is the better option, even if we lose four characters (w-z). To now generate a string of a certain length, we can simply use a 2^(length*numBits)-1 number. The last problem, if we want a string with a certain length, random could generate a small number, so the length is not met, so we have to pad the string to its required length prepending zeros.
I found this solution that generates a random hex encoded string. The provided unit test seems to hold up to my primary use case. Although, it is slightly more complex than some of the other answers provided. /** * Generate a random hex encoded string token of the specified length * * #param length * #return random hex string */ public static synchronized String generateUniqueToken(Integer length){ byte random[] = new byte[length]; Random randomGenerator = new Random(); StringBuffer buffer = new StringBuffer(); randomGenerator.nextBytes(random); for (int j = 0; j < random.length; j++) { byte b1 = (byte) ((random[j] & 0xf0) >> 4); byte b2 = (byte) (random[j] & 0x0f); if (b1 < 10) buffer.append((char) ('0' + b1)); else buffer.append((char) ('A' + (b1 - 10))); if (b2 < 10) buffer.append((char) ('0' + b2)); else buffer.append((char) ('A' + (b2 - 10))); } return (buffer.toString()); } #Test public void testGenerateUniqueToken(){ Set set = new HashSet(); String token = null; int size = 16; /* Seems like we should be able to generate 500K tokens * without a duplicate */ for (int i=0; i<500000; i++){ token = Utility.generateUniqueToken(size); if (token.length() != size * 2){ fail("Incorrect length"); } else if (set.contains(token)) { fail("Duplicate token generated"); } else{ set.add(token); } } }
Change String characters as per as your requirements. String is immutable. Here StringBuilder.append is more efficient than string concatenation. public static String getRandomString(int length) { final String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJLMNOPQRSTUVWXYZ1234567890!##$%^&*()_+"; StringBuilder result = new StringBuilder(); while(length > 0) { Random rand = new Random(); result.append(characters.charAt(rand.nextInt(characters.length()))); length--; } return result.toString(); }
import java.util.Date; import java.util.Random; public class RandomGenerator { private static Random random = new Random((new Date()).getTime()); public static String generateRandomString(int length) { char[] values = {'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t', 'u','v','w','x','y','z','0','1','2','3', '4','5','6','7','8','9'}; String out = ""; for (int i=0;i<length;i++) { int idx=random.nextInt(values.length); out += values[idx]; } return out; } }
I don't really like any of these answers regarding a "simple" solution :S I would go for a simple ;), pure Java, one liner (entropy is based on random string length and the given character set): public String randomString(int length, String characterSet) { return IntStream.range(0, length).map(i -> new SecureRandom().nextInt(characterSet.length())).mapToObj(randomInt -> characterSet.substring(randomInt, randomInt + 1)).collect(Collectors.joining()); } #Test public void buildFiveRandomStrings() { for (int q = 0; q < 5; q++) { System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything } } Or (a bit more readable old way) public String randomString(int length, String characterSet) { StringBuilder sb = new StringBuilder(); // Consider using StringBuffer if needed for (int i = 0; i < length; i++) { int randomInt = new SecureRandom().nextInt(characterSet.length()); sb.append(characterSet.substring(randomInt, randomInt + 1)); } return sb.toString(); } #Test public void buildFiveRandomStrings() { for (int q = 0; q < 5; q++) { System.out.println(randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")); // The character set can basically be anything } } But on the other hand you could also go with UUID which has a pretty good entropy: UUID.randomUUID().toString().replace("-", "")
I'm using a library from Apache Commons to generate an alphanumeric string: import org.apache.commons.lang3.RandomStringUtils; String keyLength = 20; RandomStringUtils.randomAlphanumeric(keylength); It's fast and simple!
You mention "simple", but just in case anyone else is looking for something that meets more stringent security requirements, you might want to take a look at jpwgen. jpwgen is modeled after pwgen in Unix, and is very configurable.
import java.util.*; import javax.swing.*; public class alphanumeric { public static void main(String args[]) { String nval, lenval; int n, len; nval = JOptionPane.showInputDialog("Enter number of codes you require: "); n = Integer.parseInt(nval); lenval = JOptionPane.showInputDialog("Enter code length you require: "); len = Integer.parseInt(lenval); find(n, len); } public static void find(int n, int length) { String str1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; StringBuilder sb = new StringBuilder(length); Random r = new Random(); System.out.println("\n\t Unique codes are \n\n"); for(int i=0; i<n; i++) { for(int j=0; j<length; j++) { sb.append(str1.charAt(r.nextInt(str1.length()))); } System.out.println(" " + sb.toString()); sb.delete(0, length); } } }
Here is the one-liner by abacus-common: String.valueOf(CharStream.random('0', 'z').filter(c -> N.isLetterOrDigit(c)).limit(12).toArray()) Random doesn't mean it must be unique. To get unique strings, use: N.uuid() // E.g.: "e812e749-cf4c-4959-8ee1-57829a69a80f". length is 36. N.guid() // E.g.: "0678ce04e18945559ba82ddeccaabfcd". length is 32 without '-'
You can use the following code, if your password mandatory contains numbers and alphabetic special characters: private static final String NUMBERS = "0123456789"; private static final String UPPER_ALPHABETS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String LOWER_ALPHABETS = "abcdefghijklmnopqrstuvwxyz"; private static final String SPECIALCHARACTERS = "##$%&*"; private static final int MINLENGTHOFPASSWORD = 8; public static String getRandomPassword() { StringBuilder password = new StringBuilder(); int j = 0; for (int i = 0; i < MINLENGTHOFPASSWORD; i++) { password.append(getRandomPasswordCharacters(j)); j++; if (j == 3) { j = 0; } } return password.toString(); } private static String getRandomPasswordCharacters(int pos) { Random randomNum = new Random(); StringBuilder randomChar = new StringBuilder(); switch (pos) { case 0: randomChar.append(NUMBERS.charAt(randomNum.nextInt(NUMBERS.length() - 1))); break; case 1: randomChar.append(UPPER_ALPHABETS.charAt(randomNum.nextInt(UPPER_ALPHABETS.length() - 1))); break; case 2: randomChar.append(SPECIALCHARACTERS.charAt(randomNum.nextInt(SPECIALCHARACTERS.length() - 1))); break; case 3: randomChar.append(LOWER_ALPHABETS.charAt(randomNum.nextInt(LOWER_ALPHABETS.length() - 1))); break; } return randomChar.toString(); }
You can use the UUID class with its getLeastSignificantBits() message to get 64 bit of random data, and then convert it to a radix 36 number (i.e. a string consisting of 0-9,A-Z): Long.toString(Math.abs( UUID.randomUUID().getLeastSignificantBits(), 36)); This yields a string up to 13 characters long. We use Math.abs() to make sure there isn't a minus sign sneaking in.
Here it is a Scala solution: (for (i <- 0 until rnd.nextInt(64)) yield { ('0' + rnd.nextInt(64)).asInstanceOf[Char] }) mkString("")
Using an Apache Commons library, it can be done in one line: import org.apache.commons.lang.RandomStringUtils; RandomStringUtils.randomAlphanumeric(64); Documentation
public static String randomSeriesForThreeCharacter() { Random r = new Random(); String value = ""; char random_Char ; for(int i=0; i<10; i++) { random_Char = (char) (48 + r.nextInt(74)); value = value + random_char; } return value; }
I think this is the smallest solution here, or nearly one of the smallest: public String generateRandomString(int length) { String randomString = ""; final char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890".toCharArray(); final Random random = new Random(); for (int i = 0; i < length; i++) { randomString = randomString + chars[random.nextInt(chars.length)]; } return randomString; } The code works just fine. If you are using this method, I recommend you to use more than 10 characters. A collision happens at 5 characters / 30362 iterations. This took 9 seconds.
public class Utils { private final Random RANDOM = new SecureRandom(); private final String ALPHABET = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; private String generateRandomString(int length) { StringBuffer buffer = new StringBuffer(length); for (int i = 0; i < length; i++) { buffer.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length()))); } return new String(buffer); } }
I need to decrypt a file efficiently [closed]
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers. This question does not appear to be about programming within the scope defined in the help center. Closed 4 years ago. Improve this question I am trying to decrypt an encrypted file with unknown key - the only thing I know about it is that the key is an integer x, 0 <= x < 1010 (i.e. a maximum of 10 decimal digits). public static String enc(String msg, long key) { String ans = ""; Random rand = new Random(key); for (int i = 0; i < msg.length(); i = i + 1) { char c = msg.charAt(i); int s = c; int rd = rand.nextInt() % (256 * 256); int s2 = s ^ rd; char c2 = (char) (s2); ans += c2; } return ans; } private static String tryToDecode(String string) { String returnedString = ""; long key; String msg = reader(string); for (long i = 0; i <= 999999999; i++) { System.out.println("decoding message with key + " + i); key = i; System.out.println("decoding with key: " + i + "\n" + enc(msg, key)); } return returnedString; } I expect to find the plain text The program works very slowly, is there any way to make it more efficient?
You can use Parallel Array Operations added in JAVA 8 if you are using Java 8 to achive this. The best fit for you would be to use Spliterator public void spliterate() { System.out.println("\nSpliterate:"); int[] src = getData(); Spliterator<Integer> spliterator = Arrays.spliterator(src); spliterator.forEachRemaining( n -> action(n) ); } public void action(int value) { System.out.println("value:"+value); // Perform some real work on this data here... } I am still not clear about your situation. Here some great tutorials and articles to figure out which parallel array operations of java 8 is going to help you ? http://www.drdobbs.com/jvm/parallel-array-operations-in-java-8/240166287 https://blog.rapid7.com/2015/10/28/java-8-introduction-to-parallelism-and-spliterator/
First things first: You can't println billions of lines. This will take forever, and it's pointless - you won't be able to see the text as it scrolls by, and your buffer won't save billion of lines so you couldn't scroll back up later even if you wanted to. If you prefer (and don't mind it being 2-3% slower than it otherwise would be), you can output once every hundred million keys, just so you can verify your program is making progress. You can optimize things by not concatenating Strings inside the loop. Strings are immutable, so the old code was creating a rather large number of Strings, especially in the enc method. Normally I'd use a StringBuilder, but in this case a simple character array will meet our needs. And there's one more thing we need to do that your current code doesn't do: Detect when we have the answer. If we assume that the message will only contain characters from 0-127 with no Unicode or extended ASCII, then we know we have a possible answer when the entire message contains only characters in this range. And we can also use this to further optimize, as we can then immediately discard any message that has a character outside of this range. We don't even have to finish decoding it and can move on to the next key. (If the message is of any length, the odds are that only one key will produce a decoded message with characters in that range - but it's not guaranteed, which is why I do not stop when I get to a valid message. You could probably do that, though.) Due to the way random numbers are generated in Java, anything in the seed above 32 bits is not used by the encoding/decoding algorithm. So you only need to go up to 4294967295 instead of 9999999999. (This also means the key that was originally used to encode the message might not be the key this program uses to decode it, since 2-3 keys in the 10 digit range will produce the same encoding/decoding.) private static String tryToDecode4(String msg) { String returnedString = ""; for (long i=0; i<=4294967295l; i++) { if (i % 100000000 == 0) // This part is just to see that it's making progress. Remove if desired for a small speed gain. System.out.println("Trying " + i); char[] decoded = enc4(msg, i); if (decoded == null) continue; returnedString = String.valueOf(decoded); System.out.println("decoding with key: " + i + " " + returnedString); } return returnedString; } private static char[] enc4(String msg, long key) { char[] ansC = new char[msg.length()]; Random rand = new Random(key); for(int i=0;i<msg.length();i=i+1) { char c = msg.charAt(i); int s = c; int rd = rand.nextInt()%(256*256); int s2 = s^rd; char c2 = (char)(s2); if (c2 > 127) return null; ansC[i] = c2; } return ansC; } This code finished running in a little over 3 minutes on my machine, with a message of "Hello World". This code will not work well for very short messages (3-4 characters or less.) It will not work if the message contains Unicode or extended ASCII, although it could easily be modified to do so if you know the range of characters that might be in the message.
Java Rainbow Tables- compute method
I am trying to write a program using Rainbow Tables to hash and hack passwords of length four. The algorithm for the hash value is: βππ βππππ’π = (163 β πβπππππ‘ππ ππ‘ πππ π‘πππ 0) + (162 β πβπππππ‘ππ ππ‘ πππ π‘πππ 1 + (161 β πβπππππ‘ππ ππ‘ πππ π‘πππ 2) + (160 β πβπππππ‘ππ ππ‘ πππ π‘πππ 3). I need help figuring out what I did wrong on the compute method. There are comments before the code saying what needs to be done if that will help solve the problem. public void compute() { //TODO: Add code to compute all possible 4-letter passwords - store in rainbow // Begin your possible passwords with aaaa and end with zzzz // Use hashCode(pwd) % 29 to determine the key (index) of where this element should be added to rainbow's ArrayList of ArrayLists // You will need to cast as int, such as key = (int) hashCode(pwd)%29 - key is the index of where to add this element in the rainbow ArrayList of ArrayLists if(password.length() != passwordLength){ throw new InvalidPasswordException(); } while(password.startsWith("aaaa") && password.endsWith("zzzz")){ key = (int) (hashCode(password)%29); rainbow.add(key, password); } } please let me know if anymore information is needed. EDIT: here is the entire code so all the other methods can be seen (Not all are complete yet) import java.util.*; public class HashMap implements HashMapADT{ private String password; private Long hash; private int key; private final int passwordLength = 4; ArrayList<ArrayList<PasswordMap>> rainbow; public HashMap() { password = ""; hash = -1L; key = -1; initializeHashMap(); } public HashMap(String str) { password = str; hash = hashCode(str); key = (int)(hash % 29); initializeHashMap(); } private void initializeHashMap() { //Initialize an ArrayList of 29 elements - when dividing by 29 only remainders 0 - 28 are possible rainbow = new ArrayList<>(); for(int i = 0; i < 29; i++) { rainbow.add(new ArrayList<PasswordMap>()); } compute(); } public Long hashCode(String str) throws InvalidPasswordException{ this.hash = 0L; //TODO: Calculate hashCode using hashing function based on powers of 29 return 0L; // temp - delete once hashCode method is implemented. } public void compute() { //TODO: Add code to compute all possible 4-letter passwords - store in rainbow // Begin your possible passwords with aaaa and end with zzzz // Use hashCode(pwd) % 29 to determine the key (index) of where this element should be added to rainbow's ArrayList of ArrayLists // You will need to cast as int, such as key = (int) hashCode(pwd)%29 - key is the index of where to add this element in the rainbow ArrayList of ArrayLists if(password.length() != passwordLength){ throw new InvalidPasswordException(); } while(password.startsWith("aaaa") && password.endsWith("zzzz")){ key = (int) (hashCode(password)%29); rainbow.add(key, password); } } public Long hash(String pwd) { //TODO: Return the hashcode for a given password // First, hash the password: int key = (int)(hashCode(pwd) % 29); // Use this key to determine which element in the rainbow table you should be traversing to find the hash code // Recall rainbow is an ArrayList of ArrayLists!! key = (int)(hashCode(pwd)%29); return 0L; // temp - delete once hash method is implemented. } public String hack(Long pwdHash) { String pwd=""; //TODO: Given a hashed password, pwdHash, determine the password // When identifying a correct hashed password, you will need to look at a difference RATHER THAN == // That is, //if (Math.abs(pwdHash - rainbow.get(key).get(i).getHash())<.001) - you've found your password!! // Note: key is the location of the rainbow list you should be traversing: key = (int)((pwdHash) % 29); return pwd; } #Override public String toString() { return password + ": " + hash; } }
The problem here is your while loop. while(f()) means "keep doing this as long as f() returns true". You've said "keep doing this as long as password starts with "aaaa" and password ends with "zzzz". We don't see you initialise password but if it's a four char string as described, it's impossible for it to both start with "aaaa" and end with "zzzz", so the while loop's block will never execute. If password was "aaaazzzz" so that the condition was true, then, since you never modify the value of password, the while loop would repeat forever. You probably want something like: for(int i=0;; i++) { String password = createPassword(i); rainbow.add(password, hash(password)); } ... and write a method createPassword() such that createPassword(0) returns "aaaa", createPassword(1) returns "aaab", createPassword(26) returns "aaba" and so on.
How to synchronize System Time access in a class in Java
I am writing a class that when called will call a method to use system time to generate a unique 8 character alphanumeric as a reference ID. But I have the fear that at some point, multiple calls might be made in the same millisecond, resulting in the same reference ID. How can I go about protecting this call to system time from multiple threads that might call this method simultaneously?
System time is unreliable source for Unique Ids. That's it. Don't use it. You need some form of a permanent source (UUID uses secure random which seed is provided by the OS) The system time may go/jump backwards even a few milliseconds and screw your logic entirely. If you can tolerate 64 bits only you can either use High/Low generator which is a very good compromise or cook your own recipe: like 18bits of days since beginning of 2012 (you have over 700years to go) and then 46bits of randomness coming from SecureRandom - not the best case and technically it may fail but it doesn't require external persistence.
I'd suggest to add the threadID to the reference ID. This will make the reference more unique. However, even within a thread consecutive calls to a time source may deliver identical values. Even calls to the highest resolution source (QueryPerformanceCounter) may result in identical values on certain hardware. A possible solution to this problem is testing the collected time value against its predecessor and add an increment item to the "time-stamp". You may need more than 8 characters when this should be human readable. The most efficient source for a timestamp is the GetSystemTimeAsFileTime API. I wrote some details in this answer.
You can use the UUID class to generate the bits for your ID, then use some bitwise operators and Long.toString to convert it to base-36 (alpha-numeric). public static String getId() { UUID uuid = UUID.randomUUID(); // This is the time-based long, and is predictable long msb = uuid.getMostSignificantBits(); // This contains the variant bits, and is random long lsb = uuid.getLeastSignificantBits(); long result = msb ^ lsb; // XOR String encoded = Long.toString(result, 36); // Remove sign if negative if (result < 0) encoded = encoded.substring(1, encoded.length()); // Trim extra digits or pad with zeroes if (encoded.length() > 8) { encoded = encoded.substring(encoded.length() - 8, encoded.length()); } while (encoded.length() < 8) { encoded = "0" + encoded; } } Since your character space is still smaller compared to UUID, this isn't foolproof. Test it with this code: public static void main(String[] args) { Set<String> ids = new HashSet<String>(); int count = 0; for (int i = 0; i < 100000; i++) { if (!ids.add(getId())) { count++; } } System.out.println(count + " duplicate(s)"); } For 100,000 IDs, the code performs well pretty consistently and is very fast. I start getting duplicate IDs when I increase another order of magnitude to 1,000,000. I modified the trimming to take the end of the encoded string instead of the beginning, and this greatly improved duplicate ID rates. Now having 1,000,000 IDs isn't producing any duplicates for me. Your best bet may still be to use a synchronized counter like AtomicInteger or AtomicLong and encode the number from that in base-36 using the code above, especially if you plan on having lots of IDs. Edit: Counter approach, in case you want it: private final AtomicLong counter; public IdGenerator(int start) { // start could also be initialized from a file or other // external source that stores the most recently used ID counter = new AtomicLong(start); } public String getId() { long result = counter.getAndIncrement(); String encoded = Long.toString(result, 36); // Remove sign if negative if (result < 0) encoded = encoded.substring(1, encoded.length()); // Trim extra digits or pad with zeroes if (encoded.length() > 8) { encoded = encoded.substring(0, 8); } while (encoded.length() < 8) { encoded = "0" + encoded; } } This code is thread-safe and can be accessed concurrently.