Updated and fixed JavaDoc

This commit is contained in:
Christian Basler 2015-06-18 18:25:47 +02:00
parent 6be8d51f6d
commit 1eb6851798
14 changed files with 189 additions and 57 deletions

View File

@ -44,7 +44,7 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
/**
* Use this class if you want to create a Bitmessage client.
* <p/>
* <p>
* You'll need the Builder to create a BitmessageContext, and set the following properties:
* <ul>
* <li>addressRepo</li>
@ -55,8 +55,10 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
* <li>streams</li>
* </ul>
* The default implementations in the different module builds can be used.
* <p/>
* </p>
* <p>
* The port defaults to 8444 (the default Bitmessage port)
* </p>
*/
public class BitmessageContext {
public static final int CURRENT_VERSION = 3;

View File

@ -35,8 +35,9 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
* The internal context should normally only be used for port implementations. If you need it in your client
* implementation, you're either doing something wrong, something very weird, or the BitmessageContext should
* get extended.
* <p/>
* <p>
* On the other hand, if you need the BitmessageContext in a port implementation, the same thing might apply.
* </p>
*/
public class InternalContext {
private final static Logger LOG = LoggerFactory.getLogger(InternalContext.class);

View File

@ -158,7 +158,7 @@ public class BitmessageAddress {
}
/**
* Returns the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts.
* @return the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts.
*/
public byte[] getPublicDecryptionKey() {
return publicDecryptionKey;

View File

@ -47,11 +47,11 @@ public class CryptoBox implements Streamable {
private final byte[] mac;
private byte[] encrypted;
public CryptoBox(Streamable data, byte[] encryptionKey) {
public CryptoBox(Streamable data, byte[] encryptionKey) throws IOException {
this(data, Security.keyToPoint(encryptionKey));
}
public CryptoBox(Streamable data, ECPoint K) {
public CryptoBox(Streamable data, ECPoint K) throws IOException {
curveType = 0x02CA;
// 1. The destination public key is called K.
@ -71,7 +71,7 @@ public class CryptoBox implements Streamable {
byte[] key_m = Arrays.copyOfRange(H, 32, 64);
// 7. Pad the input text to a multiple of 16 bytes, in accordance to PKCS7.
// 8. Encrypt the data with AES-256-CBC, using IV as initialization vector, key_e as encryption key and the padded input text as payload. Call the output cipher text.
encrypted = crypt(true, Bytes.from(data), key_e);
encrypted = crypt(true, Encode.bytes(data), key_e);
// 9. Calculate a 32 byte MAC with HMACSHA256, using key_m as salt and IV + R + cipher text as data. Call the output MAC.
mac = calculateMac(key_m);
@ -99,6 +99,9 @@ public class CryptoBox implements Streamable {
}
/**
* @param privateKey a private key, typically should be 32 bytes long
* @return an InputStream yielding the decrypted data
* @throws DecryptionFailedException if the payload can't be decrypted using this private key
* @see <a href='https://bitmessage.org/wiki/Encryption#Decryption'>https://bitmessage.org/wiki/Encryption#Decryption</a>
*/
public InputStream decrypt(byte[] privateKey) throws DecryptionFailedException {

View File

@ -50,7 +50,7 @@ public class GetPubkey extends ObjectPayload {
}
/**
* Returns an array of bytes that represent either the ripe, or the tag of an address, depending on the
* @return an array of bytes that represent either the ripe, or the tag of an address, depending on the
* address version.
*/
public byte[] getRipeTag() {

View File

@ -50,7 +50,7 @@ public abstract class ObjectPayload implements Streamable {
}
/**
* The ECDSA signature which, as of protocol v3, covers the object header starting with the time,
* @return the ECDSA signature which, as of protocol v3, covers the object header starting with the time,
* appended with the data described in this table down to the extra_bytes. Therefore, this must
* be checked and set in the {@link ObjectMessage} object.
*/

View File

@ -31,12 +31,15 @@ public class Label {
}
/**
* RGBA representation for the color.
* @return RGBA representation for the color.
*/
public int getColor() {
return color;
}
/**
* @param color RGBA representation for the color.
*/
public void setColor(int color) {
this.color = color;
}
@ -50,14 +53,14 @@ public class Label {
return id;
}
public Type getType() {
return type;
}
public void setId(Object id) {
this.id = id;
}
public Type getType() {
return type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -26,7 +26,7 @@ public interface AddressRepository {
BitmessageAddress findIdentity(byte[] ripeOrTag);
/**
* Returns all Bitmessage addresses that belong to this user, i.e. have a private key.
* @return all Bitmessage addresses that belong to this user, i.e. have a private key.
*/
List<BitmessageAddress> getIdentities();
@ -35,7 +35,7 @@ public interface AddressRepository {
List<BitmessageAddress> getSubscriptions(long broadcastVersion);
/**
* Returns all Bitmessage addresses that have no private key.
* @return all Bitmessage addresses that have no private key.
*/
List<BitmessageAddress> getContacts();

View File

@ -29,9 +29,8 @@ import static java.util.Arrays.copyOfRange;
* @author Christian Basler: I removed some dependencies to the BitcoinJ code so it can be used here more easily.
*/
public class Base58 {
private static char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
private static final int[] INDEXES = new int[128];
private static char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
static {
for (int i = 0; i < INDEXES.length; i++) {
@ -44,6 +43,9 @@ public class Base58 {
/**
* Encodes the given bytes in base58. No checksum is appended.
*
* @param input to encode
* @return base58 encoded input
*/
public static String encode(byte[] input) {
if (input.length == 0) {

View File

@ -38,6 +38,9 @@ public class Bytes {
/**
* Increases nonce by value, which is used as an unsigned byte value.
*
* @param nonce an unsigned number
* @param value to be added to nonce
*/
public static void inc(byte[] nonce, byte value) {
int i = nonce.length - 1;
@ -54,7 +57,7 @@ public class Bytes {
}
/**
* Returns true if a < b.
* @return true if a &lt; b.
*/
public static boolean lt(byte[] a, byte[] b) {
byte[] max = (a.length > b.length ? a : b);
@ -73,7 +76,7 @@ public class Bytes {
}
/**
* Returns true if a < b, where the first [size] bytes are used as the numbers to check.
* @return true if a &lt; b, where the first [size] bytes are used as the numbers to check.
*/
public static boolean lt(byte[] a, byte[] b, int size) {
for (int i = 0; i < size; i++) {
@ -91,7 +94,7 @@ public class Bytes {
}
/**
* Returns a new byte array of length, left-padded with '0'.
* @return a new byte array of length, left-padded with '0'.
*/
public static byte[] expand(byte[] source, int size) {
byte[] result = new byte[size];
@ -100,7 +103,7 @@ public class Bytes {
}
/**
* Returns a new byte array containing the first <em>size</em> bytes of the given array.
* @return a new byte array containing the first <em>size</em> bytes of the given array.
*/
public static byte[] truncate(byte[] source, int size) {
byte[] result = new byte[size];
@ -109,7 +112,7 @@ public class Bytes {
}
/**
* Returns the byte array that hex represents. This is meant for test use and should be rewritten if used in
* @return the byte array that hex represents. This is meant for test use and should be rewritten if used in
* production code.
*/
public static byte[] fromHex(String hex) {
@ -136,7 +139,7 @@ public class Bytes {
}
/**
* Returns the number of leading '0' of a byte array.
* @return the number of leading '0' of a byte array.
*/
public static int numberOfLeadingZeros(byte[] bytes) {
int i;
@ -145,24 +148,4 @@ public class Bytes {
}
return i;
}
/**
* Returns a copy of bytes with leading zeroes stripped.
*/
public static byte[] stripLeadingZeros(byte[] bytes) {
return Arrays.copyOfRange(bytes, numberOfLeadingZeros(bytes), bytes.length);
}
/**
* Returns the byte array of the serialized data.
*/
public static byte[] from(Streamable data) {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
data.write(out);
return out.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -25,8 +25,11 @@ public class Collections {
private final static Random RANDOM = new Random();
/**
* Returns a random subset of the given collection, or a copy of the collection if it's not larger than count.
* The randomness
* @param count the number of elements to return (if possible)
* @param collection the collection to take samples from
* @return a random subset of the given collection, or a copy of the collection if it's not larger than count. The
* result is by no means securely random, but should be random enough so not the same objects get selected over
* and over again.
*/
public static <T> List<T> selectRandom(int count, Collection<T> collection) {
ArrayList<T> result = new ArrayList<>(count);
@ -44,7 +47,7 @@ public class Collections {
} else {
result.add(item);
resultRest--;
if (resultRest == 0){
if (resultRest == 0) {
break;
}
skipMax = (int) Math.ceil(collectionRest / resultRest);

View File

@ -112,7 +112,9 @@ public class Encode {
}
/**
* Returns an array of bytes representing the given streamable object.
* @param streamable the object to be serialized
* @return an array of bytes representing the given streamable object.
* @throws IOException if an I/O error occurs.
*/
public static byte[] bytes(Streamable streamable) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
@ -121,8 +123,10 @@ public class Encode {
}
/**
* Returns the bytes of the given streamable object, 0-padded such that the final
* length is x*padding.
* @param streamable the object to be serialized
* @param padding the result will be padded such that its length is a multiple of <em>padding</em>
* @return the bytes of the given {@link Streamable} object, 0-padded such that the final length is x*padding.
* @throws IOException if an I/O error occurs.
*/
public static byte[] bytes(Streamable streamable, int padding) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();

View File

@ -40,7 +40,8 @@ import java.security.spec.KeySpec;
import java.util.Arrays;
/**
* Provides some methods to help with hashing and encryption.
* Provides some methods to help with hashing and encryption. All randoms are created using {@link SecureRandom},
* which should be secure enough.
*/
public class Security {
public static final Logger LOG = LoggerFactory.getLogger(Security.class);
@ -52,10 +53,26 @@ public class Security {
java.security.Security.addProvider(new BouncyCastleProvider());
}
/**
* A helper method to calculate SHA-512 hashes. Please note that a new {@link MessageDigest} object is created at
* each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in
* success on the same thread.
*
* @param data to get hashed
* @return SHA-512 hash of data
*/
public static byte[] sha512(byte[]... data) {
return hash("SHA-512", data);
}
/**
* A helper method to calculate doubleSHA-512 hashes. Please note that a new {@link MessageDigest} object is created
* at each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in
* success on the same thread.
*
* @param data to get hashed
* @return SHA-512 hash of data
*/
public static byte[] doubleSha512(byte[]... data) {
MessageDigest mda = md("SHA-512");
for (byte[] d : data) {
@ -64,33 +81,97 @@ public class Security {
return mda.digest(mda.digest());
}
/**
* A helper method to calculate double SHA-512 hashes. This method allows to only use a part of the available bytes
* to use for the hash calculation.
* <p>
* Please note that a new {@link MessageDigest} object is created at each call (to ensure thread safety), so you
* shouldn't use this if you need to do many hash calculations in short order on the same thread.
* </p>
*
* @param data to get hashed
* @param length number of bytes to be taken into account
* @return SHA-512 hash of data
*/
public static byte[] doubleSha512(byte[] data, int length) {
MessageDigest mda = md("SHA-512");
mda.update(data, 0, length);
return mda.digest(mda.digest());
}
/**
* A helper method to calculate RIPEMD-160 hashes. Supplying multiple byte arrays has the same result as a
* concatenation of all arrays, but might perform better.
* <p>
* Please note that a new {@link MessageDigest} object is created at
* each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in short
* order on the same thread.
* </p>
*
* @param data to get hashed
* @return RIPEMD-160 hash of data
*/
public static byte[] ripemd160(byte[]... data) {
return hash("RIPEMD160", data);
}
/**
* A helper method to calculate double SHA-256 hashes. This method allows to only use a part of the available bytes
* to use for the hash calculation.
* <p>
* Please note that a new {@link MessageDigest} object is created at
* each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in short
* order on the same thread.
* </p>
*
* @param data to get hashed
* @param length number of bytes to be taken into account
* @return SHA-256 hash of data
*/
public static byte[] doubleSha256(byte[] data, int length) {
MessageDigest mda = md("SHA-256");
mda.update(data, 0, length);
return mda.digest(mda.digest());
}
/**
* A helper method to calculate SHA-1 hashes. Supplying multiple byte arrays has the same result as a
* concatenation of all arrays, but might perform better.
* <p>
* Please note that a new {@link MessageDigest} object is created at
* each call (to ensure thread safety), so you shouldn't use this if you need to do many hash calculations in short
* order on the same thread.
* </p>
*
* @param data to get hashed
* @return SHA hash of data
*/
public static byte[] sha1(byte[]... data) {
return hash("SHA-1", data);
}
/**
* @param length number of bytes to return
* @return an array of the given size containing random bytes
*/
public static byte[] randomBytes(int length) {
byte[] result = new byte[length];
RANDOM.nextBytes(result);
return result;
}
public static void doProofOfWork(ObjectMessage object, ProofOfWorkEngine worker, long nonceTrialsPerByte, long extraBytes) {
/**
* Calculates the proof of work. This might take a long time, depending on the hardware, message size and time to
* live.
*
* @param object to do the proof of work for
* @param worker doing the actual proof of work
* @param nonceTrialsPerByte difficulty
* @param extraBytes bytes to add to the object size (makes it more difficult to send small messages)
*/
public static void doProofOfWork(ObjectMessage object, ProofOfWorkEngine worker, long nonceTrialsPerByte,
long extraBytes) {
try {
if (nonceTrialsPerByte < 1000) nonceTrialsPerByte = 1000;
if (extraBytes < 1000) extraBytes = 1000;
@ -107,9 +188,13 @@ public class Security {
}
/**
* @throws InsufficientProofOfWorkException if proof of work doesn't check out
* @param object to be checked
* @param nonceTrialsPerByte difficulty
* @param extraBytes bytes to add to the object size
* @throws InsufficientProofOfWorkException if proof of work doesn't check out (makes it more difficult to send small messages)
*/
public static void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException {
public static void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes)
throws IOException {
byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes);
byte[] value = Security.doubleSha512(object.getNonce(), getInitialHash(object));
if (Bytes.lt(target, value, 8)) {
@ -146,6 +231,13 @@ public class Security {
}
}
/**
* Calculates the MAC for a message (data)
*
* @param key_m the symmetric key used
* @param data the message data to calculate the MAC for
* @return the MAC
*/
public static byte[] mac(byte[] key_m, byte[] data) {
try {
Mac mac = Mac.getInstance("HmacSHA256", "BC");
@ -156,6 +248,18 @@ public class Security {
}
}
/**
* Create a new public key fom given private keys.
*
* @param version of the public key / address
* @param stream of the address
* @param privateSigningKey private key used for signing
* @param privateEncryptionKey private key used for encryption
* @param nonceTrialsPerByte proof of work difficulty
* @param extraBytes bytes to add for the proof of work (make it harder for small messages)
* @param features of the address
* @return a public key object
*/
public static Pubkey createPubkey(long version, long stream, byte[] privateSigningKey, byte[] privateEncryptionKey,
long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
return Factory.createPubkey(version, stream,
@ -164,10 +268,18 @@ public class Security {
nonceTrialsPerByte, extraBytes, features);
}
/**
* @param privateKey private key as byte array
* @return a public key corresponding to the given private key
*/
public static ECPoint createPublicKey(byte[] privateKey) {
return EC_CURVE_PARAMETERS.getG().multiply(keyToBigInt(privateKey)).normalize();
}
/**
* @param privateKey private key as byte array
* @return a big integer representation (unsigned) of the given bytes
*/
public static BigInteger keyToBigInt(byte[] privateKey) {
return new BigInteger(1, privateKey);
}
@ -185,7 +297,13 @@ public class Security {
);
}
public static boolean isSignatureValid(byte[] bytesToSign, byte[] signature, Pubkey pubkey) {
/**
* @param data to check
* @param signature the signature of the message
* @param pubkey the sender's public key
* @return true if the signature is valid, false otherwise
*/
public static boolean isSignatureValid(byte[] data, byte[] signature, Pubkey pubkey) {
try {
ECParameterSpec spec = new ECParameterSpec(
EC_CURVE_PARAMETERS.getCurve(),
@ -201,13 +319,20 @@ public class Security {
Signature sig = Signature.getInstance("ECDSA", "BC");
sig.initVerify(publicKey);
sig.update(bytesToSign);
sig.update(data);
return sig.verify(signature);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Calculate the signature of data, using the given private key.
*
* @param data to be signed
* @param privateKey to be used for signing
* @return the signature
*/
public static byte[] getSignature(byte[] data, ch.dissem.bitmessage.entity.valueobject.PrivateKey privateKey) {
try {
ECParameterSpec spec = new ECParameterSpec(
@ -231,6 +356,9 @@ public class Security {
}
}
/**
* @return a random number of type long
*/
public static long randomNonce() {
return RANDOM.nextLong();
}

View File

@ -30,7 +30,7 @@ public class UnixTime {
public static final long DAY = 24 * HOUR;
/**
* Returns the time in second based Unix time ({@link System#currentTimeMillis()}/1000)
* @return the time in second based Unix time ({@link System#currentTimeMillis()}/1000)
*/
public static long now() {
return System.currentTimeMillis() / 1000;
@ -38,6 +38,9 @@ public class UnixTime {
/**
* Same as {@link #now()} + shiftSeconds, but might be more readable.
*
* @param shiftSeconds number of seconds from now we're interested in
* @return the Unix time in shiftSeconds seconds / shiftSeconds seconds ago
*/
public static long now(long shiftSeconds) {
return (System.currentTimeMillis() / 1000) + shiftSeconds;