package org.bitseal.crypt; import java.math.BigInteger; import org.bitseal.core.AddressProcessor; import org.bitseal.core.App; import org.bitseal.core.BehaviourBitfieldProcessor; import org.bitseal.data.Address; import org.bitseal.data.Pubkey; import org.bitseal.database.AddressProvider; import org.bitseal.database.PubkeyProvider; import org.bitseal.util.TimeUtils; import org.spongycastle.jce.interfaces.ECPrivateKey; public class PubkeyGenerator { /** The object type number for pubkeys, as defined by the Bitmessage protocol */ private static final int OBJECT_TYPE_PUBKEY = 1; /** The 'time to live' value (in seconds) that we will use when creating new pubkey objects. */ private static final long PUBKEY_TTL = 172800; // Currently set to 2 days /** In Bitmessage protocol version 3, the network standard value for nonce trials per byte is 1000. */ public static final int NETWORK_NONCE_TRIALS_PER_BYTE = 1000; /** In Bitmessage protocol version 3, the network standard value for extra bytes is 1000. */ public static final int NETWORK_EXTRA_BYTES = 1000; /** * Generates a new Pubkey object for the given Address and saves it * to the app's database. Also updates the "correspondingPubkeyId" field * of the given Address and updates that Address's record in the database. * * @param address - The Address object to generate a Pubkey for * * @return A Pubkey object for the given Address */ public Pubkey generateAndSaveNewPubkey(Address address) { // Generate a new pubkey Pubkey pubkey = generateNewPubkey(address); // Save the new pubkey to the database PubkeyProvider pubProv = PubkeyProvider.get(App.getContext()); long pubkeyId = pubProv.addPubkey(pubkey); pubkey.setId(pubkeyId); // Finally, set the "correspondingPubkeyId" of the Address we started with to match the ID of the Pubkey we have just generated // Note: We retrieve the Address from the database rather than using the one passed to this method so that any changes // that have been made to the address since this method began (e.g. the user updating the address's label) will not be lost. AddressProvider addProv = AddressProvider.get(App.getContext()); Address addressFromDatabase = addProv.searchForSingleRecord(address.getId()); addressFromDatabase.setCorrespondingPubkeyId(pubkeyId); addProv.updateAddress(addressFromDatabase); return pubkey; } /** * Generates a Pubkey object for a given Address object. Used to create a new pubkey * for one of my addresses. <br><br> * * @param address - The Address object for which we want to generate a Pubkey * * @return A Pubkey object corresponding to the given Address object. */ private Pubkey generateNewPubkey(Address address) { // Derive the public keys from the private keys of the address KeyConverter keyConv = new KeyConverter(); ECPrivateKey privateSigningKey = keyConv.decodePrivateKeyFromWIF(address.getPrivateSigningKey()); ECPrivateKey privateEncryptionKey = keyConv.decodePrivateKeyFromWIF(address.getPrivateEncryptionKey()); BigInteger privateSigningKeyDValue = privateSigningKey.getD(); BigInteger privateEncryptionKeyDValue = privateEncryptionKey.getD(); ECKeyPair signingKeyPair = new ECKeyPair(privateSigningKeyDValue); ECKeyPair encryptionKeyPair = new ECKeyPair(privateEncryptionKeyDValue); byte[] publicSigningKey = signingKeyPair.getPubKey(); byte[] publicEncryptionKey = encryptionKeyPair.getPubKey(); // Get the address version and stream number AddressProcessor addProc = new AddressProcessor(); int[] decoded = addProc.decodeAddressNumbers(address.getAddress()); int addressVersion = decoded[0]; int streamNumber = decoded[1]; // Set the Behaviour Bitfield. int behaviourBitfield = BehaviourBitfieldProcessor.getBitfieldForMyPubkeys(); // Work out the 'end of life time' value to use long expirationTime = TimeUtils.getFuzzedExpirationTime(PUBKEY_TTL); // Create a new Pubkey object and populate its fields. Pubkey pubkey = new Pubkey(); pubkey.setCorrespondingAddressId(address.getId()); pubkey.setBelongsToMe(true); pubkey.setRipeHash(address.getRipeHash()); pubkey.setExpirationTime(expirationTime); pubkey.setObjectType(OBJECT_TYPE_PUBKEY); pubkey.setObjectVersion(addressVersion); pubkey.setStreamNumber(streamNumber); pubkey.setBehaviourBitfield(behaviourBitfield); pubkey.setPublicSigningKey(publicSigningKey); pubkey.setPublicEncryptionKey(publicEncryptionKey); pubkey.setNonceTrialsPerByte(NETWORK_NONCE_TRIALS_PER_BYTE); pubkey.setExtraBytes(NETWORK_EXTRA_BYTES); // Generate the signature for this pubkey SigProcessor sigProc = new SigProcessor(); byte[] signaturePayload = sigProc.createPubkeySignaturePayload(pubkey); byte[] signature = sigProc.signWithWIFKey(signaturePayload, address.getPrivateSigningKey()); pubkey.setSignature(signature); pubkey.setSignatureLength(signature.length); return pubkey; } }