1958

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".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Todd
  • 3,363
  • 3
  • 21
  • 12
  • 163
    Beware [the birthday paradox](http://en.wikipedia.org/wiki/Birthday_problem). – pablosaraiva Oct 25 '10 at 15:07
  • 63
    Even taking the birthday paradox in consideration, if you use 12 alphanumeric characters (62 total), you would still need well over 34 billion strings to reach the paradox. And the birthday paradox doesn't guarantee a collision anyways, it just says it's over 50% chance. – NullUserException Oct 29 '12 at 04:13
  • 6
    @NullUserException 50 % success chance (per try) is damn high: even with 10 attempts, success rate is 0.999. With that and the fact that you can try A LOT in a period of 24 hours in mind, you don't need 34 billion strings to be pretty sure to guess at least one of them. That is the reason why some session tokens should be really, really long. – Pijusn Jan 31 '15 at 10:28
  • This blogpost should be useful - code for producing alphanumeric strings: http://www.rationaljava.com/2015/06/java8-generate-random-string-in-one-line.html – Dan Jun 23 '15 at 14:06
  • 20
    These 3 single line codes are very much useful i guess.. `Long.toHexString(Double.doubleToLongBits(Math.random()));` `UUID.randomUUID().toString();` `RandomStringUtils.randomAlphanumeric(12);` – Manindar Jun 08 '16 at 07:31
  • 25
    @Pijusn I know this is old, but... the "50% chance" in the birthday paradox is **NOT** "per try", it's "50% chance that, out of (in this case) 34 billion strings, there exists at least one pair of duplicates". You'd need 1.6 *sept*illion - 1.6e21 - entries in your database in order for there to be a 50% chance per try. – Tin Wizard Oct 11 '17 at 19:21
  • It's better to remove `"-"` in the string – cwtuan Oct 11 '22 at 07:17
  • [random string using javascript,Java, Python, Rust, bash](https://fe-tool.com/en-us/random-password) – cwtuan Dec 21 '22 at 07:46

46 Answers46

1628

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.

Community
  • 1
  • 1
erickson
  • 265,237
  • 58
  • 395
  • 493
  • 6
    If you need spaces in yours, you can tack on `.replaceAll("\\d", " ");` onto the end of the `return new BigInteger(130, random).toString(32);` line to do a regex swap. It replaces all digits with spaces. Works great for me: I'm using this as a substitute for a front-end Lorem Ipsum – weisjohn Oct 07 '11 at 15:00
  • 4
    @weisjohn That's a good idea. You can do something similar with the second method, by removing the digits from `symbols` and using a space instead; you can control the average "word" length by changing the number of spaces in symbols (more occurrences for shorter words). For a really over-the-top fake text solution, you can use a Markov chain! – erickson Oct 07 '11 at 16:02
  • 4
    These identifiers are randomly selected from space of a certain size. They could be 1 character long. If you want a fixed length, you can use the second solution, with a `SecureRandom` instance assigned to the `random` variable. – erickson Dec 20 '11 at 00:15
  • 17
    @ejain because 32 = 2^5; each character will represent exactly 5 bits, and 130 bits can be evenly divided into characters. – erickson Feb 21 '12 at 21:38
  • 3
    @erickson `BigInteger.toString(int)` doesn't work that way, it's actually calling `Long.toString(long, String)` to determine the character values (which gives a better JavaDoc description of what it actually does). Essentially doing `BigInteger.toString(32)` just means you only get characters `0-9` + `a-v` rather than `0-9` + `a-z`. – Vala Aug 29 '12 at 15:51
  • 1
    @erickson I don't know what you were saying about it, but it seemed to include bits coming in to it, which the `BigInteger.toString(int)` method never uses. It's using `char[]`s and I don't see how 130 bits is relevant in any respect. You also seem to be saying using 32 instead of 36 is of some benefit, which I can't see any evidence of either. That's not to say I couldn't be missing something, but your explanation doesn't make it obvious. – Vala Aug 30 '12 at 00:05
  • 1
    @Thor84no Saying that the method doesn't work "that way" implies you have a clear idea of what I was saying, and that what I was saying was wrong. Anyhow, at least 128 bits is preferred for strong security. 25 base-32 digits will only hold 125 bits, so you need 26 base-32 digits. But, 32^26 exactly equals 2^130, so you can squeeze a couple of extra bits in without any additional characters. If you use base 36 instead, you can fit 129 bits into 25 characters, but there is some wasted space (a quarter of a bit). – erickson Aug 30 '12 at 04:16
  • for swift: http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710#26845710 – iAhmed May 26 '16 at 11:25
  • Kotlin Version (and Kotlin Script to run it directly from the console): https://gist.github.com/corlaez/c73351af76cc6b36c342170534b29bf6 – corlaez Jun 10 '20 at 17:37
  • The implementation is **not thread safe**, because `buf` is a field, and therefore shared between invocations of `nextString()`. Naive use of this in a multi-threaded application (e.g. by declaring it as a singleton Bean in a Spring Framework web application) could easily lead to duplicate identifiers or other, more insidious, security issues. If `buf` were declared inside `nextString()` it would be fine. – Jelaby Aug 18 '22 at 09:40
  • That’s right @Jelaby. A better approach would be to have your singleton be a factory that produces properly constructed instances to be injected into request-scoped objects that need them. These are lightweight objects and creating one for each use should pose no problem if needed. Other thread-safe singletons that might be appropriate for a given application include a proxy that provides locking for a single instance, or a proxy that manages a thread-local instance. – erickson Aug 18 '22 at 14:17
  • I don't think any of those other approaches are better in this case. There's really no downside in creating `buf` inside `nextString()`, unless you're doing something quite extreme that requires optimisation, but the upside is that you _can_ use the class exactly as you'd _expect_ to be able to use it, following the Principle of Least Astonishment. All these other options require additional work that's not immediately obvious (no matter that making a bean request-scoped is a 1-line change in Spring), and that could be terrible for performance (e.g. the locking proxy). – Jelaby Aug 20 '22 at 11:55
  • By the way, you cloud use [random string generator](https://fe-tool.com/en-us/random-password) online. – cwtuan Oct 11 '22 at 07:15
  • @Jelaby Originally, methods on many core library classes like `StringBuffer` and collections were synchronized in a naïve attempt to provide thread-safety. After the initial release, practice proved that these types were seldom shared between threads, and even when they were, additional synchronization was needed for correctness. Since Java 2's collection framework, later `StringBuilder`, etc., classes are consistent in requiring developers to manage concurrency. Unless specifically documented for concurrent use, there is no expectation of thread-safety, and no surprise at its absence. – erickson Oct 11 '22 at 16:01
  • @erickson Actually, the push has been to _document_ how developers need to manage concurrency, and built-in classes are consistent in doing so. We are also fairly clearly talking about an enterprise-like environment, where actually the general expectation is that all classes are "services" with no internal state unless otherwise documented. My opinion is that having `buf` be a field rather than a variable is a micro-optimisation that breaks expected behaviour, and that the computational and congnitive complexity of handling it isn't worth it in virtuall every case. – Jelaby May 23 '23 at 17:24
893

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • 36
    Beware that this solution only generates a random string with hexadecimal characters. Which can be fine in some cases. – Dave May 05 '11 at 09:28
  • 6
    The UUID class is useful. However, they aren't as compact as the identifiers produced by my answers. This can be an issue, for example, in URLs. Depends on your needs. – erickson Aug 24 '11 at 16:37
  • 6
    @Ruggs - The goal is *alpha-numeric strings.* How does broadening the output to any possible bytes fit with that? – erickson Oct 07 '11 at 16:18
  • 75
    According to RFC4122 using UUID's as tokens is a bad idea: Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example. A predictable random number source will exacerbate the situation. http://www.ietf.org/rfc/rfc4122.txt – Somatik Dec 31 '12 at 11:31
  • 1
    @Somatik - So what should you use instead of UUIDs? – Drew S Nov 14 '13 at 17:04
  • 38
    `UUID.randomUUID().toString().replaceAll("-", "");` makes the string alpha-numeric, as requested. – Numid Jan 22 '14 at 09:58
  • 4
    @Numid I have never seen something between g and z in a UUID. – Patrick Bergner Feb 11 '14 at 14:33
  • 2
    @PatrickBergner is right. The suggestion above only produces a sequence of hexadecimal digits. – Numid Feb 12 '14 at 07:09
  • 1
    What about MD5 on this output? It's should be more difficult to guess. – uriel May 02 '15 at 19:46
  • 2
    Just use base 64 if you want it to be hashed and alpha-numeric. – ThePyroEagle Dec 24 '15 at 11:24
  • @Somatik UUID.randomUUID() actually uses SecureRandom. Still might not be a good idea if you want 128bit encryption. You will only get 122bits of random: http://stackoverflow.com/questions/7532807/are-java-random-uuids-predictable – Micro Feb 08 '16 at 01:10
  • 1
    This will generate a 36 characters string. (32 hex digits + 4 dashes), not more. – Charles Follet Jan 03 '17 at 13:44
637
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();
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
maxp
  • 5,454
  • 7
  • 28
  • 30
  • 72
    +1, the simplest solution here for generating a random string *of specified length* (apart from using RandomStringUtils from Commons Lang). – Jonik Apr 20 '12 at 15:49
  • 15
    Consider using `SecureRandom` instead of the `Random` class. If passwords are generated on a server, it might be vulnerable to timing attacks. – foens Jun 25 '14 at 13:34
  • 10
    I would add lowercase also: `AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";` and some other allowed chars. – ACV Sep 07 '15 at 20:56
  • Thanks! I added the lowercase letters and some special characters as well. – Robert Martin Jan 06 '16 at 21:46
  • 1
    Why not put `static Random rnd = new Random();` inside the method? – Micro Feb 08 '16 at 01:25
  • 6
    @MicroR Is there a good reason to create the `Random` object in each method invocation? I don't think so. – cassiomolin Feb 15 '16 at 10:49
  • for swift: http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710#26845710 – iAhmed May 26 '16 at 11:25
504

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cmsherratt
  • 2,129
  • 3
  • 15
  • 13
  • 23
    Has just looked through **mentioned class** of `Apache Commons Lang 3.3.1` library - and it is using only `java.util.Random` to provide random sequences, so it is producing **insecure sequences**. – Yuriy Nakonechnyy Apr 03 '14 at 14:51
  • 16
    Make sure you use SecureRandom when using RandomStringUtils: `public static java.lang.String random(int count, int start, int end, boolean letters, boolean numbers, @Nullable char[] chars, java.util.Random random)` – Ruslans Uralovs Mar 03 '15 at 13:28
  • DO NOT USE. This creates *insecure sequences*! – Patrick Apr 04 '19 at 13:03
  • 2
    Build your `RandomStringGenerator` using this so that the sequences are secure: `new RandomStringGenerator.Builder().usingRandom(RANDOM::nextInt).build();` – Rohan Sep 14 '20 at 21:36
  • 1
    @YuriyNakonechnyy return RandomStringUtils.random(12, 0, length, true, true,characterSetArray, new SecureRandom()); here characterSetArray is the set of characters you would want. Example (say all numbers and all small cases) will be "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray(). And length is the length of characterArray – anuj pradhan Sep 06 '21 at 12:03
143

You can use an Apache Commons library for this, RandomStringUtils:

RandomStringUtils.randomAlphanumeric(20).toUpperCase();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Manish Singh
  • 5,848
  • 4
  • 43
  • 31
  • Is this function guarantee to generate unique results if called at different times – kml_ckr Sep 24 '12 at 11:31
  • 20
    @kamil, I looked at the source code for RandomStringUtils, and it uses an instance of java.util.Random instantiated without arguments. The documentation for java.util.Random says it uses current system time if no seed is provided. This means that it can not be used for session identifiers/keys since an attacker can easily predict what the generated session identifiers are at any given time. – Inshallah Sep 26 '12 at 10:14
  • 44
    @Inshallah : You are (unnecessarily) overengineering the system. While I agree that it uses time as seed, the attacker has to have the access to following data to to actually get what he wants 1. Time to the exact millisecond, when the code was seeded 2. Number of calls that have occurred so far 3. Atomicity for his own call (so that number of calls-so-far ramains same) If your attacker has all three of these things, then you have much bigger issue at hand... – Ajeet Ganga Oct 13 '13 at 23:36
  • Just random. The probability of collision is very less. – Manish Singh Oct 17 '14 at 16:57
  • 4
    gradle dependency: `compile 'commons-lang:commons-lang:2.6' ` – younes0 Jan 19 '15 at 14:35
  • 5
    @Ajeet this isn't true. You can derive the state of the random number generator from its output. If an attacker can generate a few thousand calls to generate random API tokens the attacker will be able to predict all future API tokens. – Thomas Grainger Dec 20 '16 at 13:52
  • 5
    @AjeetGanga Nothing to do with over engineering. If you want to create session ids, you need a cryptographic pseudo random generator. Every prng using time as seed is predictable and very insecure for data that should be unpredictable. Just use `SecureRandom` and you are good. – Patrick Sep 19 '17 at 10:37
  • 1
    Since `commons-lang` `3.6`, `RandomStringUtils` is deprecated in favor of `RandomStringGenerator` of `commons-text` – numéro6 Oct 17 '17 at 09:31
  • For an Up, which one is the maven dependency? – NaN Jul 05 '21 at 22:29
115

In one line:

Long.toHexString(Double.doubleToLongBits(Math.random()));

Source: Java - generating a random string

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 2
    It helped me too but only hexadecimal digits :( – noquery Sep 05 '11 at 05:31
  • @Zippoxer, you could concat that several times =) – daniel.bavrin May 17 '14 at 15:10
  • 7
    The OP's example showed the following String as an example `AEYGF7K0DM1X` which is not hexadecimal. It worries me how often people mistake alphanumeric with hexadecimal. They are not the same thing. – hfontanez Nov 20 '14 at 02:31
  • @daniel.bavrin, Zippoxer means hexadecimal string has only 6 letters (ABCDEF). He is not talking about the length, it doesn't matter how many times you concat – jcesarmobile Jan 16 '15 at 08:34
  • 9
    This is much less random than it should be given the string length as `Math.random()` produces a `double` between 0 and 1, so the exponent part is mostly unused. Use `random.nextLong` for a random `long` instead of this ugly hack. – maaartinus Jul 22 '15 at 01:13
89

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 bits 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.

Comparison of token sizes

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 bits, 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 bits, creating a 40% overhead. This will use A-Z and 2-7, making it reasonably space efficient while being case-insensitive alphanumeric. There isn't any standard implementation in the JDK. Example encoding 16 bytes without padding: WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (hexadecimal) every character encodes four bits, 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 alphanumeric)

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 (omits leading zeros)
}

//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);
Patrick
  • 33,984
  • 10
  • 106
  • 126
  • 3
    This answer is complete and works without adding any dependency. If you want to avoid possible minus signs in the output, you can prevent negative `BigInteger`s using a constructor parameter: `BigInteger(1, token)` instead of `BigInteger(token)`. – francoisr Jul 11 '17 at 07:50
  • Tanks @francoisr for the hint, I edited the code example – Patrick Jul 11 '17 at 08:38
  • `import java.security.SecureRandom;` and `import java.math.BigInteger;` are needed to make the example work, but it works great! – anothermh Oct 04 '18 at 01:45
  • Good answer but /dev/random is a blocking method which is the reason it is slow to the point of blocking if entropy is too low. The better and non-blocking method is /dev/urandom. This can be configured via /lib/security/java.security and set securerandom.source=file:/dev/./urandom – Muzammil May 10 '20 at 16:27
  • @Muzammil See https://tersesystems.com/blog/2015/12/17/the-right-way-to-use-securerandom/ (also linked in the answer) - `new SecureRandom()` uses `/dev/urandom` – Patrick May 11 '20 at 08:25
  • Be careful that that answer does not **always** produce a string of the max expected lenght. For example, with an entropy of 16 bytes and and hexa encoding (`toString(16)`), you can have string of size 32 most of the time, but also shorter ones when you draw a byte array encoding to a bit int with leading zeros. For ex, `new BigInteger("0166703753569646828446735315886151238", 10).toString(16).size == 30`. This happen quite often, so if the string length must be stable, you will need to check for it and redraw accordingly, or just concatenate several draws together to have the required length. – fanf42 Jun 28 '23 at 08:18
  • True, it depends if the logic sees the bytes as a number, then leading "0" are omitted or as byte string. You are right that BigInteger behaves that way, I added a comment – Patrick Jun 29 '23 at 09:05
42

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dfa
  • 114,442
  • 31
  • 189
  • 228
36

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
Apocalisp
  • 34,834
  • 8
  • 106
  • 155
  • 4
    This will produce **insecure sequences** i.e. sequences which can be easily guessed. – Yuriy Nakonechnyy Apr 03 '14 at 14:53
  • 9
    All this double-infested random int generation is broken by design, slow and unreadable. Use `Random#nextInt` or `nextLong`. Switch to `SecureRandom` if needed. – maaartinus Jul 22 '15 at 01:17
35

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user unknown
  • 35,537
  • 11
  • 75
  • 121
  • 11
    Just keep in mind, that there is a 50 % chance of a minus sign infront of the result ! So wrapping r.nextLong() in a Math.abs() can be used, if you don't want the minus sign: `Long.toString(Math.abs(r.nextLong()), 36);` – Ray Hulha Jan 27 '13 at 02:12
  • 5
    @RayHulha: If you don't want the minus sign, you should cut it off, because, surprisingly, Math.abs returns a negative value for Long.MIN_VALUE. – user unknown Jan 27 '13 at 13:28
  • Interesting the Math.abs returning negative. More here: http://bmaurer.blogspot.co.nz/2006/10/mathabs-returns-negative-number.html – Phil Nov 10 '13 at 20:34
  • 1
    The issue with `abs` is solved by using a bitwise operator to clear the most significant bit. This will work for all values. – Radiodef Apr 02 '18 at 23:27
  • 1
    @Radiodef That's essentially what @userunkown said. I suppose you could also do `<< 1 >>> 1`. – shmosel Apr 02 '18 at 23:35
32

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Michael Allen
  • 5,712
  • 3
  • 38
  • 63
18

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();
}
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
Howard Lovatt
  • 968
  • 1
  • 8
  • 15
  • 3
    That's great - but if you want to keep it to strictly alphanumeric (0-9, a-z, A-Z) see here http://www.rationaljava.com/2015/06/java8-generate-random-string-in-one-line.html – Dan Jun 23 '15 at 14:08
12
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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rina
  • 21
  • 1
  • 2
11
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cmpbah
  • 21
  • 1
  • 2
  • 1
    I allowed myself to make some minor modifications. Why do you add `+ 0` that often? Why do you split declaration of spot and initialisxation? What is the advantage of indexes 1,2,3,4 instead of 0,1,2,3? Most importantly: you took a random value, and compared with if-else 4 times a new value, which could always mismatch, without gaining more randomness. But feel free to rollback. – user unknown Apr 17 '12 at 09:50
11

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kristian Kraljic
  • 826
  • 12
  • 11
9

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);
        }
    }
}
Ankush soni
  • 1,439
  • 1
  • 15
  • 30
Todd
  • 3,363
  • 3
  • 21
  • 12
8
  1. Change String characters as per as your requirements.

  2. 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();
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
deepakmodak
  • 1,329
  • 13
  • 16
  • 3
    This adds nothing the dozens of answers given previously didn't cover. And creating a new `Random` instance in each iteration of the loop is inefficient. – erickson Feb 10 '14 at 05:17
7

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("-", "")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Patrik Bego
  • 4,009
  • 1
  • 26
  • 24
7

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!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chuong Tran
  • 17
  • 2
  • 2
7
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;
    }
}
Ankush soni
  • 1,439
  • 1
  • 15
  • 30
Jameskittu
  • 598
  • 2
  • 8
  • 17
6
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);
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Suganya
  • 11
  • 1
  • 1
6

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.

michaelok
  • 1,124
  • 1
  • 13
  • 20
  • Thanks, fixed it. So it least there is source and the link is valid. On the downside, it doesn't look like it has been updated in a while, though I see pwgen has been updated fairly recently. – michaelok Jun 26 '17 at 22:50
5

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 '-'
user_3380739
  • 1
  • 14
  • 14
4

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();
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prasobh.Kollattu
  • 1,665
  • 1
  • 22
  • 32
4

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
neuhaus
  • 1
  • 1
  • 1
  • 3
    Why in the world would you use UUID to get random bits? Why not just use `random.nextLong()`? Or even `Double.doubleToLongBits(Math.random())`? – erickson Oct 04 '13 at 05:31
3

Here it is a Scala solution:

(for (i <- 0 until rnd.nextInt(64)) yield { 
  ('0' + rnd.nextInt(64)).asInstanceOf[Char] 
}) mkString("")
3

Using an Apache Commons library, it can be done in one line:

import org.apache.commons.lang.RandomStringUtils;
RandomStringUtils.randomAlphanumeric(64);

Documentation

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
hridayesh
  • 1,123
  • 1
  • 14
  • 36
3
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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
duggu
  • 37,851
  • 12
  • 116
  • 113
  • 2
    That string concatenation is unnecessarily inefficient. And the crazy indentation makes your code nearly unreadable. This is the same as [Jamie's idea,](http://stackoverflow.com/a/13686133/3474) but poorly executed. – erickson Oct 04 '13 at 05:36
3

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
FileInputStream
  • 126
  • 2
  • 11
3
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);
    } 
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
2
public static String getRandomString(int length)
{
    String randomStr = UUID.randomUUID().toString();
    while(randomStr.length() < length) {
        randomStr += UUID.randomUUID().toString();
    }
    return randomStr.substring(0, length);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vin
  • 11
  • 1
  • 4
    This is pretty much the same as [Steve McLeod's answer](http://stackoverflow.com/a/41762/3474) given two years previously. – erickson Oct 04 '13 at 05:40
2
public static String getRandomString(int length) {
    char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST".toCharArray();

    StringBuilder sb = new StringBuilder();
    Random random = new Random();
    for (int i = 0; i < length; i++) {
        char c = chars[random.nextInt(chars.length)];
        sb.append(c);
    }
    String randomStr = sb.toString();

    return randomStr;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prasad Parab
  • 437
  • 1
  • 7
  • 26
  • 1
    Really nice! But it should be `length` instead of `chars.length` in the for loop: `for (int i = 0; i < length; i++)` – Incinerator Aug 29 '19 at 13:19
1

Best Random String Generator Method

public class RandomStringGenerator{

    private static int randomStringLength = 25 ;
    private static boolean allowSpecialCharacters = true ;
    private static String specialCharacters = "!@$%*-_+:";
    private static boolean allowDuplicates = false ;

    private static boolean isAlphanum = false;
    private static boolean isNumeric = false;
    private static boolean isAlpha = false;
    private static final String alphabet = "abcdefghijklmnopqrstuvwxyz";
    private static boolean mixCase = false;
    private static final String capAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String num = "0123456789";

    public static String getRandomString() {
        String returnVal = "";
        int specialCharactersCount = 0;
        int maxspecialCharacters = randomStringLength/4;

        try {
            StringBuffer values = buildList();
            for (int inx = 0; inx < randomStringLength; inx++) {
                int selChar = (int) (Math.random() * (values.length() - 1));
                if (allowSpecialCharacters)
                {
                    if (specialCharacters.indexOf("" + values.charAt(selChar)) > -1)
                    {
                        specialCharactersCount ++;
                        if (specialCharactersCount > maxspecialCharacters)
                        {
                            while (specialCharacters.indexOf("" + values.charAt(selChar)) != -1)
                            {
                                selChar = (int) (Math.random() * (values.length() - 1));
                            }
                        }
                    }
                }
                returnVal += values.charAt(selChar);
                if (!allowDuplicates) {
                    values.deleteCharAt(selChar);
                }
            }
        } catch (Exception e) {
            returnVal = "Error While Processing Values";
        }
        return returnVal;
    }

    private static StringBuffer buildList() {
        StringBuffer list = new StringBuffer(0);
        if (isNumeric || isAlphanum) {
            list.append(num);
        }
        if (isAlpha || isAlphanum) {
            list.append(alphabet);
            if (mixCase) {
                list.append(capAlpha);
            }
        }
        if (allowSpecialCharacters)
        {
            list.append(specialCharacters);
        }
        int currLen = list.length();
        String returnVal = "";
        for (int inx = 0; inx < currLen; inx++) {
            int selChar = (int) (Math.random() * (list.length() - 1));
            returnVal += list.charAt(selChar);
            list.deleteCharAt(selChar);
        }
        list = new StringBuffer(returnVal);
        return list;
    }   

}
Bhavik Ambani
  • 6,557
  • 14
  • 55
  • 86
1

There are lots of use of StringBuilder in previous answers. I guess it's easy, but it requires a function call per character, growing an array, etc...

If using the stringbuilder, a suggestion is to specify the required capacity of the string, i.e.,

new StringBuilder(int capacity);

Here's a version that doesn't use a StringBuilder or String appending, and no dictionary.

public static String randomString(int length)
{
    SecureRandom random = new SecureRandom();
    char[] chars = new char[length];
    for(int i=0; i<chars.length; i++)
    {
        int v = random.nextInt(10 + 26 + 26);
        char c;
        if (v < 10)
        {
            c = (char)('0' + v);
        }
        else if (v < 36)
        {
            c = (char)('a' - 10 + v);
        }
        else
        {
            c = (char)('A' - 36 + v);
        }
        chars[i] = c;
    }
    return new String(chars);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jamie
  • 1,888
  • 1
  • 18
  • 21
1

You can create a character array which includes all the letters and numbers, and then you can randomly select from this character array and create your own string password.

char[] chars = new char[62]; // Sum of letters and numbers

int i = 0;

for(char c = 'a'; c <= 'z'; c++) { // For letters
    chars[i++] = c;
}

for(char c = '0'; c <= '9';c++) { // For numbers
    chars[i++] = c;
}

for(char c = 'A'; c <= 'Z';c++) { // For capital letters
    chars[i++] = c;
}

int numberOfCodes = 0;
String code = "";
while (numberOfCodes < 1) { // Enter how much you want to generate at one time
    int numChars = 8; // Enter how many digits you want in your password

    for(i = 0; i < numChars; i++) {
        char c = chars[(int)(Math.random() * chars.length)];
        code = code + c;
    }
    System.out.println("Code is:" + code);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Burak T
  • 67
  • 1
  • 3
  • 8
1

Maybe this is helpful

package password.generater;

import java.util.Random;

/**
 *
 * @author dell
 */
public class PasswordGenerater {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int length= 11;
        System.out.println(generatePswd(length));

        // TODO code application logic here
    }
    static char[] generatePswd(int len){
        System.out.println("Your Password ");
        String charsCaps="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
        String Chars="abcdefghijklmnopqrstuvwxyz";
        String nums="0123456789";
        String symbols="!@#$%^&*()_+-=.,/';:?><~*/-+";
        String passSymbols=charsCaps + Chars + nums +symbols;
        Random rnd=new Random();
        char[] password=new char[len];

        for(int i=0; i<len;i++){
            password[i]=passSymbols.charAt(rnd.nextInt(passSymbols.length()));
        }
      return password;

    }
}
pratik mankar
  • 126
  • 1
  • 10
1

You can do this in one line with no external libraries.

int length = 12;
String randomString = new Random().ints(48, 122).filter(i -> (i < 58 || i > 64) && (i < 91 || i > 96)).limit(length).collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
System.out.print(randomString);

I have separated out the length into a parameter, and added a line to print the result.

This code creates a stream of random integers bounded to the alphanumeric ascii range. It then filters out some symbols, because the alphanumeric range is not continuous. It then limits the length and collects the result into a string.

Because this approach discards something like 20% of the numbers/characters it generates (as they are symbols), there is a small performance impact.

I don't find it particularly readable, but I don't think anyone else has suggested a native Java solution in one line.

F_SO_K
  • 13,640
  • 5
  • 54
  • 83
0

I have developed an application to develop an autogenerated alphanumberic string for my project. In this string, the first three characters are alphabetical and the next seven are integers.

public class AlphaNumericGenerator {

    public static void main(String[] args) {
        java.util.Random r = new java.util.Random();
        int i = 1, n = 0;
        char c;
        String str = "";
        for (int t = 0; t < 3; t++) {
            while (true) {
                i = r.nextInt(10);
                if (i > 5 && i < 10) {

                    if (i == 9) {
                        i = 90;
                        n = 90;
                        break;
                    }
                    if (i != 90) {
                        n = i * 10 + r.nextInt(10);
                        while (n < 65) {
                            n = i * 10 + r.nextInt(10);
                        }
                    }
                    break;
                }
            }
            c = (char)n;

            str = String.valueOf(c) + str;
        }

        while(true){
            i = r.nextInt(10000000);
            if(i > 999999)
                break;
        }
        str = str + i;
        System.out.println(str);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

Here's a simple one-liner using UUIDs as the character base and being able to specify (almost) any length. (Yes, I know that using a UUID has been suggested before.)

public static String randString(int length) {
    return UUID.randomUUID().toString().replace("-", "").substring(0, Math.min(length, 32)) + (length > 32 ? randString(length - 32) : "");
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
aaronvargas
  • 12,189
  • 3
  • 52
  • 52
0

Here is a Java 8 solution based on streams.

    public String generateString(String alphabet, int length) {
        return generateString(alphabet, length, new SecureRandom()::nextInt);
    }

    // nextInt = bound -> n in [0, bound)
    public String generateString(String source, int length, IntFunction<Integer> nextInt) {
        StringBuilder sb = new StringBuilder();
        IntStream.generate(source::length)
                .boxed()
                .limit(length)
                .map(nextInt::apply)
                .map(source::charAt)
                .forEach(sb::append);

        return sb.toString();
    }

Use it like

String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int length = 12;
String generated = generateString(alphabet, length);
System.out.println(generated);

The function nextInt should accept an int bound and return a random number between 0 and bound - 1.

mike
  • 4,929
  • 4
  • 40
  • 80
0
public static String RandomAlphanum(int length)
{
    String charstring = "abcdefghijklmnopqrstuvwxyz0123456789";
    String randalphanum = "";
    double randroll;
    String randchar;
    for (double i = 0; i < length; i++)
    {
        randroll = Math.random();
        randchar = "";
        for (int j = 1; j <= 35; j++)
        {
            if (randroll <= (1.0 / 36.0 * j))
            {
                randchar = Character.toString(charstring.charAt(j - 1));
                break;
            }
        }
        randalphanum += randchar;
    }
    return randalphanum;
}

I used a very primitive algorithm using Math.random(). To increase randomness, you can directly implement the util.Date class. Nevertheless, it works.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Riley Jones
  • 43
  • 1
  • 8
0

Given the some characters (AllCharacters), you could pickup a character in the string randomly. Then use-for loop to get random charcter repeatedly.

public class MyProgram {
  static String getRandomString(int size) {
      String AllCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      StringBuilder sb = new StringBuilder(size);
      int length = AllCharacters.length();
      for (int i = 0; i < size; i++) {
          sb.append(AllCharacters.charAt((int)(length * Math.random())));
      }
      return sb.toString();
  }

  public static void main(String[] args) {
      System.out.println(MyProgram.getRandomString(30));
  }
}
cwtuan
  • 1,718
  • 1
  • 18
  • 20
-1

Yet another solution...

public static String generatePassword(int passwordLength) {
    int asciiFirst = 33;
    int asciiLast = 126;
    Integer[] exceptions = { 34, 39, 96 };

    List<Integer> exceptionsList = Arrays.asList(exceptions);
    SecureRandom random = new SecureRandom();
    StringBuilder builder = new StringBuilder();
    for (int i=0; i<passwordLength; i++) {
        int charIndex;

        do {
            charIndex = random.nextInt(asciiLast - asciiFirst + 1) + asciiFirst;
        }
        while (exceptionsList.contains(charIndex));

        builder.append((char) charIndex);
    }
    return builder.toString();
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steven L
  • 15,304
  • 1
  • 21
  • 16
-1

Also, you can generate any lowercase or uppercase letters or even special characters through data from the ASCII table. For example, generate upper case letters from A (DEC 65) to Z (DEC 90):

String generateRandomStr(int min, int max, int size) {
    String result = "";
    for (int i = 0; i < size; i++) {
        result += String.valueOf((char)(new Random().nextInt((max - min) + 1) + min));
    }
    return result;
}

Generated output for generateRandomStr(65, 90, 100));:

TVLPFQJCYFXQDCQSLKUKKILKKHAUFYEXLUQFHDWNMRBIRRRWNXNNZQTINZPCTKLHGHVYWRKEOYNSOFPZBGEECFMCOKWHLHCEWLDZ
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kyxap
  • 516
  • 6
  • 20
-1

Efficient and short.

/**
 * Utility class for generating random Strings.
 */
public interface RandomUtil {

    int    DEF_COUNT = 20;
    Random RANDOM    = new SecureRandom();

    /**
     * Generate a password.
     *
     * @return the generated password
     */
    static String generatePassword() {
        return generate(true, true);
    }

    /**
     * Generate an activation key.
     *
     * @return the generated activation key
     */
    static String generateActivationKey() {
        return generate(false, true);
    }

    /**
     * Generate a reset key.
     *
     * @return the generated reset key
     */
    static String generateResetKey() {
        return generate(false, true);
    }

    static String generate(boolean letters, boolean numbers) {
        int
            start = ' ',
            end   = 'z' + 1,
            count = DEF_COUNT,
            gap   = end - start;
        StringBuilder builder = new StringBuilder(count);

        while (count-- != 0) {
            int codePoint = RANDOM.nextInt(gap) + start;

            switch (getType(codePoint)) {
                case UNASSIGNED:
                case PRIVATE_USE:
                case SURROGATE:
                    count++;
                    continue;
            }

            int numberOfChars = charCount(codePoint);

            if (count == 0 && numberOfChars > 1) {
                count++;
                continue;
            }

            if (letters && isLetter(codePoint)
                || numbers && isDigit(codePoint)
                || !letters && !numbers) {

                builder.appendCodePoint(codePoint);
                if (numberOfChars == 2)
                    count--;
            }
            else
                count++;
        }
        return builder.toString();
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SoBeRich
  • 682
  • 2
  • 8
  • 15
-1

I am using a very simple solution using Java 8. Just customize it according to your needs.

...
import java.security.SecureRandom;
...

//Generate a random String of length between 10 to 20.
//Length is also randomly generated here.
SecureRandom random = new SecureRandom();

String sampleSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";

int stringLength = random.ints(1, 10, 21).mapToObj(x -> x).reduce((a, b) -> a).get();

String randomString = random.ints(stringLength, 0, sampleSet.length() - 1)
        .mapToObj(x -> sampleSet.charAt(x))
        .collect(Collector
            .of(StringBuilder::new, StringBuilder::append,
                StringBuilder::append, StringBuilder::toString));

We can use this to generate an alphanumeric random String like this (the returned String will mandatorily have some non-numeric characters as well as some numeric characters):

public String generateRandomString() {
            
    String sampleSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
    String sampleSetNumeric = "0123456789";
    
    String randomString = getRandomString(sampleSet, 10, 21);
    String randomStringNumeric = getRandomString(sampleSetNumeric, 10, 21);
    
    randomString = randomString + randomStringNumeric;
    
    //Convert String to List<Character>
    List<Character> list = randomString.chars()
            .mapToObj(x -> (char)x)
            .collect(Collectors.toList());
    
    Collections.shuffle(list);
    
    //This is needed to force a non-numeric character as the first String
    //Skip this for() if you don't need this logic

    for(;;) {
        if(Character.isDigit(list.get(0))) Collections.shuffle(list);
        else break;
    }
    
    //Convert List<Character> to String
    randomString = list.stream()
            .map(String::valueOf)
            .collect(Collectors.joining());
    
    return randomString;
    
}

//Generate a random number between the lower bound (inclusive) and upper bound (exclusive)
private int getRandomLength(int min, int max) {
    SecureRandom random = new SecureRandom();
    return random.ints(1, min, max).mapToObj(x -> x).reduce((a, b) -> a).get();
}

//Generate a random String from the given sample string, having a random length between the lower bound (inclusive) and upper bound (exclusive)
private String getRandomString(String sampleSet, int min, int max) {
    SecureRandom random = new SecureRandom();
    return random.ints(getRandomLength(min, max), 0, sampleSet.length() - 1)
    .mapToObj(x -> sampleSet.charAt(x))
    .collect(Collector
        .of(StringBuilder::new, StringBuilder::append,
            StringBuilder::append, StringBuilder::toString));
}
Mayank
  • 79
  • 6