
cc.youchain.crypto.WalletUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
YOUChain Common library in JAVA.
The newest version!
package cc.youchain.crypto;
import java.io.File;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import cc.youchain.utils.Numeric;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import static cc.youchain.crypto.Hash.sha256;
import static cc.youchain.crypto.Keys.ADDRESS_LENGTH_IN_HEX;
import static cc.youchain.crypto.Keys.PRIVATE_KEY_LENGTH_IN_HEX;
/** Utility functions for working with Wallet files. */
public class WalletUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final SecureRandom secureRandom = SecureRandomUtils.secureRandom();
static {
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
public static String generateFullNewWalletFile(String password, File destinationDirectory)
throws NoSuchAlgorithmException, NoSuchProviderException,
InvalidAlgorithmParameterException, CipherException, IOException {
return generateNewWalletFile(password, destinationDirectory, true);
}
public static String generateLightNewWalletFile(String password, File destinationDirectory)
throws NoSuchAlgorithmException, NoSuchProviderException,
InvalidAlgorithmParameterException, CipherException, IOException {
return generateNewWalletFile(password, destinationDirectory, false);
}
public static String generateNewWalletFile(String password, File destinationDirectory)
throws CipherException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchProviderException, IOException {
return generateFullNewWalletFile(password, destinationDirectory);
}
public static String generateNewWalletFile(
String password, File destinationDirectory, boolean useFullScrypt)
throws CipherException, IOException, InvalidAlgorithmParameterException,
NoSuchAlgorithmException, NoSuchProviderException {
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
return generateWalletFile(password, ecKeyPair, destinationDirectory, useFullScrypt);
}
public static String generateWalletFile(
String password, ECKeyPair ecKeyPair, File destinationDirectory, boolean useFullScrypt)
throws CipherException, IOException {
WalletFile walletFile;
if (useFullScrypt) {
walletFile = Wallet.createStandard(password, ecKeyPair);
} else {
walletFile = Wallet.createLight(password, ecKeyPair);
}
String fileName = getWalletFileName(walletFile);
File destination = new File(destinationDirectory, fileName);
objectMapper.writeValue(destination, walletFile);
return fileName;
}
/**
* Generates a BIP-39 compatible Ethereum wallet. The private key for the wallet can be
* calculated using following algorithm:
*
*
* Key = SHA-256(BIP_39_SEED(mnemonic, password))
*
*
* @param password Will be used for both wallet encryption and passphrase for BIP-39 seed
* @param destinationDirectory The directory containing the wallet
* @return A BIP-39 compatible Ethereum wallet
* @throws CipherException if the underlying cipher is not available
* @throws IOException if the destination cannot be written to
*/
public static Bip39Wallet generateBip39Wallet(String password, File destinationDirectory)
throws CipherException, IOException {
byte[] initialEntropy = new byte[16];
secureRandom.nextBytes(initialEntropy);
String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy);
byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
ECKeyPair privateKey = ECKeyPair.create(sha256(seed));
String walletFile = generateWalletFile(password, privateKey, destinationDirectory, false);
return new Bip39Wallet(walletFile, mnemonic);
}
/**
* Generates a BIP-39 compatible Ethereum wallet using a mnemonic passed as argument.
*
* @param password Will be used for both wallet encryption and passphrase for BIP-39 seed
* @param mnemonic The mnemonic that will be used to generate the seed
* @param destinationDirectory The directory containing the wallet
* @return A BIP-39 compatible Ethereum wallet
* @throws CipherException if the underlying cipher is not available
* @throws IOException if the destination cannot be written to
*/
public static Bip39Wallet generateBip39WalletFromMnemonic(
String password, String mnemonic, File destinationDirectory)
throws CipherException, IOException {
byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
ECKeyPair privateKey = ECKeyPair.create(sha256(seed));
String walletFile = generateWalletFile(password, privateKey, destinationDirectory, false);
return new Bip39Wallet(walletFile, mnemonic);
}
public static Credentials loadCredentials(String password, String source)
throws IOException, CipherException {
return loadCredentials(password, new File(source));
}
public static Credentials loadCredentials(String password, File source)
throws IOException, CipherException {
WalletFile walletFile = objectMapper.readValue(source, WalletFile.class);
return Credentials.create(Wallet.decrypt(password, walletFile));
}
public static Credentials loadBip39Credentials(String password, String mnemonic) {
byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
return Credentials.create(ECKeyPair.create(sha256(seed)));
}
/**
* Load credentials from JSON wallet string.
*
* @param password - password to decrypt JSON wallet string
* @param content - JSON wallet content string
* @return Ethereum credentials
* @throws CipherException if the underlying cipher is not available
* @throws IOException if a low-level I/O problem (unexpected end-of-input, network error)
* occurs
*/
public static Credentials loadJsonCredentials(String password, String content)
throws IOException, CipherException {
WalletFile walletFile = objectMapper.readValue(content, WalletFile.class);
return Credentials.create(Wallet.decrypt(password, walletFile));
}
private static String getWalletFileName(WalletFile walletFile) {
DateTimeFormatter format =
DateTimeFormatter.ofPattern("'UTC--'yyyy-MM-dd'T'HH-mm-ss.nVV'--'");
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
return now.format(format) + walletFile.getAddress() + ".json";
}
public static String getDefaultKeyDirectory() {
return getDefaultKeyDirectory(System.getProperty("os.name"));
}
static String getDefaultKeyDirectory(String osName1) {
String osName = osName1.toLowerCase();
if (osName.startsWith("mac")) {
return String.format(
"%s%sLibrary%sEthereum",
System.getProperty("user.home"), File.separator, File.separator);
} else if (osName.startsWith("win")) {
return String.format("%s%sEthereum", System.getenv("APPDATA"), File.separator);
} else {
return String.format("%s%s.ethereum", System.getProperty("user.home"), File.separator);
}
}
public static String getTestnetKeyDirectory() {
return String.format(
"%s%stestnet%skeystore", getDefaultKeyDirectory(), File.separator, File.separator);
}
public static String getMainnetKeyDirectory() {
return String.format("%s%skeystore", getDefaultKeyDirectory(), File.separator);
}
/**
* Get keystore destination directory for a Rinkeby network.
*
* @return a String containing destination directory
*/
public static String getRinkebyKeyDirectory() {
return String.format(
"%s%srinkeby%skeystore", getDefaultKeyDirectory(), File.separator, File.separator);
}
public static boolean isValidPrivateKey(String privateKey) {
String cleanPrivateKey = Numeric.cleanHexPrefix(privateKey);
return cleanPrivateKey.length() == PRIVATE_KEY_LENGTH_IN_HEX;
}
public static boolean isValidAddress(String input) {
return isValidAddress(input, ADDRESS_LENGTH_IN_HEX);
}
public static boolean isValidAddress(String input, int addressLength) {
String cleanInput = Numeric.cleanHexPrefix(input);
try {
Numeric.toBigIntNoPrefix(cleanInput);
} catch (NumberFormatException e) {
return false;
}
return cleanInput.length() == addressLength;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy