General Concepts

Some general concepts apply to all functionalities in Bruce.

Algorithms

Algorithms supported by the default JCA provider are listed here.

Algorithms supported by the Bouncy Castle JCA provider are listed here.

Method Overloading

Most methods allow choosing the most appropriate version through overloading.

Static Imports

Static imports are assumed through all examples. Instead of:

import com.mirkocaserta.bruce.Bruce;

Digester digester = Bruce.digester("SHA1");

the examples assume:

import static com.mirkocaserta.bruce.Bruce.digester;

Digester digester = digester("SHA1");

You are of course free not to use static imports. I personally like them as the code looks a bit tidier.

Passwords

Passwords in the API are typed as a char array. There is a good reason for this: depending on implementation specifics, String instances might be stored in a permanent memory area.

One might argue that accessing this memory area is not easy task for an attacker, but there's plenty of reasons why this is not always the case.

So, Bruce only accepts passwords as char arrays. If you are working with passwords that are already arriving to you in a String instance, just call .toCharArray() on it to perform the conversion where necessary.

Encoding

Raw byte arrays

At the most basic level, computers work with bits. In Java, you can work at the bit level, but the most basic form of storage for encrypted data is the byte. At low level, Java cryptography usually works on arrays of bytes, such as:

public static final byte[] MESSAGE_SHA1 = new byte[]{
        (byte) 0x6f, (byte) 0x9b, (byte) 0x9a, (byte) 0xf3,
        (byte) 0xcd, (byte) 0x6e, (byte) 0x8b, (byte) 0x8a,
        (byte) 0x73, (byte) 0xc2, (byte) 0xcd, (byte) 0xce,
        (byte) 0xd3, (byte) 0x7f, (byte) 0xe9, (byte) 0xf5,
        (byte) 0x92, (byte) 0x26, (byte) 0xe2, (byte) 0x7d
};

Digester digester = digester("SHA1");
byte[] hash = digester.digest("message".getBytes(StandardCharsets.UTF_8));

The MESSAGE_SHA1 and hash byte arrays are identical. You can easily see however how this is not always a very practical representation format. You cannot directly use this value in a text file, an email message or a JSON payload.

Encodings

For these reasons all methods that work with raw byte arrays also have an overloaded version that supports different encodings.

EncodingDigester digester = digester("SHA1", BASE64);
String hash = digester.digest("message");

The hash String is going to look like this, as it gets base64 encoded: "b5ua881ui4pzws3O03/p9ZIm4n0=".

Supported encodings are Base64, Url, Mime, Hex.

Base64, email and 7 bits

SMTP, the protocol the Internet uses for sending emails, - in its original form - was designed to transport 7-bit ASCII characters only. Base64 works around this limitation by using characters that fit in a 7-bit space.

Cipher encoding vs charset encoding

Please do not confuse the cipher encoding with the message character encoding. They are different things in the API parameters, and they are different Java types in Bruce so any confusion results in a compiler error.

Providers

All methods allow specifying an optional JCA provider.

For instance, to use the Bouncy Castle provider with a digester:

// use the Bouncy Castle provider
EncodingDigester digester = digester("SHA1", "BC", HEX);

I won't provide documentation for all overloaded methods that allow specifying a custom provider, otherwise the documentation would become even more verbose than it already is. Just know that the methods are there if you need them.

Do not forget to add the appropriate provider jar to the classpath for this to work.

Error Handling

There is a single exception in Bruce that wraps all kinds of errors: the BruceException. As it is a RuntimeException, you are not forced to catch it.

Initialization and configuration errors are raised as soon as possible.

Wherever possible, the originating exception is wrapped and can be accessed through the getCause() method.

Last updated