What is the most time efficient way to create and Base32 encode a random UUID in Java? I would like to use Base32 encoding to store globally unique IDs that are usable in URLs.
Base32 still pads with the = character, so you'll need to do something with that if you really want to avoid URL escaping.
If you really want to avoid Base16, I recommend you use Base64 instead of Base32. If you want to use an RFC standard, try base64url. However, that standard also uses "=" for the trailing padding, so you need to escape that. It's substitutions are:
+ -> -
/ -> _
= -> =
Personally, I use a variant called Y64. It's substitutions are:
+ -> .
/ -> _
= -> -
It's not an RFC standard, but at least you don't have to worry about escaping the trailing "=".
Apache Commons Codec provides both Base64 and Base32. Here's an example with Base64 with the Y64 variant
To encode:
UUID uuid = UUID.randomUUID();
ByteBuffer uuidBuffer = ByteBuffer.allocate(16);
LongBuffer longBuffer = uuidBuffer.asLongBuffer();
longBuffer.put(uuid.getMostSignificantBits());
longBuffer.put(uuid.getLeastSignificantBits());
String encoded = new String(Base64.encode(uuidBuffer.array()),
Charset.forName("US-ASCII"));
encoded = encoded.replace('+', '.')
.replace('/', '_')
.replace('=', '-');
And decode:
String encoded; // from your request parameters or whatever
encoded = encoded.replace('.', '+')
.replace('_', '/')
.replace('-', '=');
ByteBuffer uuidBuffer = ByteBuffer.wrap(Base64.decode(
encoded.getBytes(Charset.forName("US-ASCII"))));
LongBuffer longBuffer = uuidBuffer.asLongBuffer();
UUID uuid = new UUID(longBuffer.get(), longBuffer.get());
I agreed with the discussion that Base64Url might be more suitable but I also see the benefit of generating unique value in Base32. It's case insensitive that is easier to handle if human is involved.
This is my code to convert UUID to Base32 using Guava's BaseEncoding.
public static String toBase32(UUID uuid){
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return BaseEncoding.base32().omitPadding().encode(bb.array());
}
The codec Base32Codec can encode UUIDs efficiently to base-32.
// Returns a base-32 string
// uuid::: 01234567-89AB-4DEF-A123-456789ABCDEF
// base32: aerukz4jvng67ijdivtytk6n54
String string = Base32Codec.INSTANCE.encode(uuid);
There are codecs for other encodings in the same package of uuid-creator.
Related
hi i'm trying to decode two strings then use the return result (byte[]) then put it in a Biginteger constructor Like this :
BigInteger bigInteger1 = new BigInteger(1, Base64.decode(myString1,0));
BigInteger bigInteger2 = new BigInteger(1, Base64.decode(myString2,0));
then put this BigIntegers on a java.security.KeyFactory class to create a RSAPublicKey like This :
KeyFactory.getInstance(ALG).generatePublic(new RSAPublicKeySpec(bigInteger1,bigInteger2));
then use my public key to encode a string Like this :
public static String encrypt(PublicKey publicKey, String str) {
Cipher instance = Cipher.getInstance(ALG);
instance.init(1, publicKey);
Base64.encodeToString(instance.doFinal(str.getBytes()), 2);
}
on PHP. I achieve this goal with android but when I want to do it with PHP I have a lot of problems even on the start when I want to decode my string in PHP with this code :
$encoded = base64_decode($base,true);
$decoded = utf8_decode(base64_decode($encoded));
I will get this string:??2?]????5N?[??S
but in android, the decoded string is totally different and always stay the same result
I tried to do this job on JSP but it's really hard to learn a new language and I don't have the time.
Can I do this project in spring boot? I have the codes for java
please, somebody, help me.
You're decoding string twice. You should try :
$encoded = base64_encode($base); // and not base64_decode
$decoded = base64_decode($encoded); // will be $base
utf8_decode is converting a string with ISO-8859-1 characters encoded with UTF-8 to single-byte ISO-8859-1. Are you sure you're needing it ?
In PHP, you can use intval to performs BigInteger() but I'm not sure you won't be facing an integer overflow.
Finally, OpenSSL library will certainly do the job for key generation and encryption.
I need to convert a RSA PublicKey into a valid JWK. Especially the values "n" an "e" of the JWK are the ones I'm struggling with. The encoding does not seem to be correct, when looking at example JWK's at https://www.rfc-editor.org/rfc/rfc7517#page-25
Currently my code looks basically like this:
private Map<String, Object> generateJWK(PublicKey publicKey){
RSAPublicKey rsa = (RSAPublicKey) publicKey;
Map<String, Object> values = new HashMap<>();
values.put("kty", rsa.getAlgorithm()); // getAlgorithm() returns kty not algorithm
values.put("kid", "someuniqueid");
values.put("n", Base64.encode(rsa.getModulus().toString()));
values.put("e", Base64.encode(rsa.getPublicExponent().toString()));
values.put("alg", "RS256");
values.put("use", "sig");
return values;
}
The output however does not seem to be correctly encoded or something, e for example looks like this: NjU1Mzc=
n does not include special characters like -, _ and + . :
jMzk1MNT0xTk2NED1xzzgNyQ00IykADzMAM0c0wz0M0MONj2z5TgNzI3yAM0OONYzzMjzwNzDxgAzxDxzMMAjTwNNDYMINMgNQDOEAkIM2jMQzkjUTDUYONNg1A00Tw1Nx4YEzAzjUT1MTNMjDjMM1MNNAjyTMIzxNADDINQANwT5yTDEMjEzNz2z2gOgjDDDNyNDjTzz43ETOYMI35gDjE00MYYM2DzDjDgww53Mwz0ME1NMgOM3MIzYTzMwzOMIQU5MjOzUjMNQNNg50U5NIDNzw2DMMOggNcQQM21TI5NMzDTN5Mj123O33MNNMkyNTNONxMM5wMMc04jTgAUE3MM1zMg4NNMT4MNDMM5yTO2j4jNDEMy1yNANNAzOIEUDzNwzExwTIkNjUjkN54Uz0DT5x0zM51k2MxYkx0zMNzxMkDUDTTQN3gAYODATQDDwMDMjMMcONjxMNTYMT5kgxNkMjNMQU0jzMEwIIMzTzUD4MgYDkDNzcAzN0TN4yNTz11DMxDUjDM2MyDMy4DEINMwT22QxjNNEzNDATy1OM1NNDxYgz5TxDkj3gQ32kIwNNkDO3xczDAENcTMNO0MOjTDwE3g11wNUcgNTwQk30kjjNNzTz4jTj4OOjQNYzMzcMjTQMkyzNNNUQOTOMMkMMMNzwNxDOEkg4xADIT4DNxMz2TENT4yN4z2I2zjyMU3DTOEQN4MIQjNDMU5Y11QkccwMNI0kNzyNjMMN4NMTTNMzMwxMjjDzgAANO1zwjYIEUjM1ADgDNjxTITMNNkIYxzyzzEEDMzDzNjzM4NjNNjc3ITTD0T5jzN=
Am I assuming right that both values n and e are not properly encoded?
How should I convert the PublicKey to JWK? (Can not use 3rd party libraries)
JWK uses base64url encoding which is slighly different to base64. Additionally, do not use toString() method on BigInteger values. Get directly the data as byte array
Change
Base64.encode(rsa.getModulus().toString())
Base64.encode(rsa.getPublicExponent().toString())
To
Base64.getUrlEncoder().encodeToString(rsa.getModulus().toByteArray())
Base64.getUrlEncoder().encodeToString(rsa.getPublicExponent().toByteArray())
code below works fine, use Apache Base64, search by phrases
RFC 4648 vs RFC 2045 codec difference
and
java biginteger to byte array leading zero
private static byte[] toByteArray(BigInteger bigInteger)
{
byte[] bytes = bigInteger.toByteArray();
byte[] result;
if ((bigInteger.bitLength() % 8 == 0) && (bytes[0] == 0) && bytes.length > 1)
{
result = new byte[bytes.length - 1];
System.arraycopy(bytes, 1, result, 0, result.length);
}
else {result = bytes;}
return result;
}
...
import org.apache.commons.codec.binary.Base64;
...
jwk.put("n", Base64.encodeBase64URLSafeString(toByteArray(publicKey.getModulus()) ) );
jwk.put("e", Base64.encodeBase64URLSafeString(publicKey.getPublicExponent().toByteArray()) );
There are some SO quetions but no helped me. I would like to convert byte[] from org.apache.commons.codec.digest.HmacUtils to String. This code produces some weird output:
final String value = "value";
final String key = "key";
byte[] bytes = HmacUtils.hmacSha1(key, value);
String s = new String(bytes);
What am I doing wrong?
Try to use:
String st = HmacUtils.hmacSha1Hex(key, value);
First, the result of hmacSha1 would produce a digest, not not a clear String. Besides, you may have to specify an encoding format, for example
String s = new String(bytes, "US-ASCII");
or
String s = new String(bytes, "UTF-8");
For a more general solution, if you don't have HmacUtils available:
// Prepare a buffer for the string
StringBuilder builder = new StringBuilder(bytes.length*2);
// Iterate through all bytes in the array
for(byte b : bytes) {
// Convert them into a hex string
builder.append(String.format("%02x",b));
// builder.append(String.format("%02x",b).toUpperCase()); // for upper case characters
}
// Done
String s = builder.toString();
To explain your problem:
You are using a hash function. So a hash is usually an array of bytes which should look quite random.
If you use new String(bytes) you try to create a string from these bytes. But Java will try to convert the bytes to characters.
For example: The byte 65 (hex 0x41) becomes the letter 'A'. 66 (hex 0x42) the letter 'B' and so on. Some numbers can't be converted into readable characters. Thats why you see strange characters like '�'.
So new String(new byte[]{0x41, 0x42, 0x43}) will become 'ABC'.
You want something else: You want each byte converted into a 2 digit hex String (and append these strings).
Greetings!
You may need to have an encoding format. Check out this link here.
UTF-8 byte[] to String
Can any character be encoded in UTF-16 (using java) ?
I thought it could but my code that encodes as
CharsetEncoder encoder = Charset.forName("UTF-16LE").newEncoder();
ByteBuffer bb = encoder.encode(CharBuffer.wrap((String) value + '\0'));
has thrown a CharacterCodingException
Unfortunately as this only occurred for a customer not myself I dont have details of the offending character.
There are possible values of char that are not valid UTF-16 sequences. For example:
CharsetEncoder encoder = Charset.forName("UTF-16LE").newEncoder();
ByteBuffer bb = encoder.encode(CharBuffer.wrap("\uDFFF"));
This code will throw an exception. U+DFFF is an unpaired surrogate.
I have a string in UTF-8 format. I want to convert it to clean ANSI format. How to do that?
You could use a java function like this one here to convert from UTF-8 to ISO_8859_1 (which seems to be a subset of ANSI):
private static String convertFromUtf8ToIso(String s1) {
if(s1 == null) {
return null;
}
String s = new String(s1.getBytes(StandardCharsets.UTF_8));
byte[] b = s.getBytes(StandardCharsets.ISO_8859_1);
return new String(b, StandardCharsets.ISO_8859_1);
}
Here is a simple test:
String s1 = "your utf8 stringáçﬠ";
String res = convertFromUtf8ToIso(s1);
System.out.println(res);
This prints out:
your utf8 stringáç?
The ﬠ character gets lost because it cannot be represented with ISO_8859_1 (it has 3 bytes when encoded in UTF-8). ISO_8859_1 can represent á and ç.
You can do something like this:
new String("your utf8 string".getBytes(Charset.forName("utf-8")));
in this format 4 bytes of UTF8 converts to 8 bytes of ANSI
Converting UTF-8 to ANSI is not possible generally, because ANSI only has 128 characters (7 bits) and UTF-8 has up to 4 bytes. That's like converting long to int, you lose information in most cases.