• Web3j钱包 -- java版本


    基于Web3j的钱包工具类,包括普通钱包的生成和加载,bip39钱包的生成和加载,bip39钱包签名和验证。

    相关依赖

    <dependency>
    	<groupId>org.web3j</groupId>
    	<artifactId>core</artifactId>
    	<version>4.2.0</version>
    </dependency>
    
    <dependency>
    	<groupId>org.projectlombok</groupId>
    	<artifactId>lombok</artifactId>
    	<version>1.18.12</version>
    	<optional>true</optional>
    </dependency>
    
    <dependency>
    	<groupId>com.alibaba</groupId>
    	<artifactId>fastjson</artifactId>
    	<version>1.2.31</version>
    </dependency>
    
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.10.3</version>
    </dependency>
    
    <dependency>
    	<groupId>org.apache.commons</groupId>
    	<artifactId>commons-lang3</artifactId>
    	<version>3.3.9</version>
    </dependency>
    
    <dependency>
    	<groupId>org.junit.jupiter</groupId>
    	<artifactId>junit-jupiter</artifactId>
    	<version>5.5.2</version>
    </dependency>
    

    安全随机数

    import org.web3j.crypto.LinuxSecureRandom;
    
    import java.security.SecureRandom;
    
    /**
     * @author ming
     * @version 1.0.0
     * @date 2020/9/23 16:05
     **/
    public class SecureRandomUtils {
        private static final SecureRandom SECURE_RANDOM;
        private static int isAndroid;
    
        public static SecureRandom secureRandom() {
            return SECURE_RANDOM;
        }
    
        private static boolean isAndroidRuntime() {
            if (isAndroid == -1) {
                String runtime = System.getProperty("java.runtime.name");
                isAndroid = runtime != null && "Android Runtime".equals(runtime) ? 1 : 0;
            }
    
            return isAndroid == 1;
        }
    
        private SecureRandomUtils() {
        }
    
        static {
            if (isAndroidRuntime()) {
                new LinuxSecureRandom();
            }
    
            SECURE_RANDOM = new SecureRandom();
            isAndroid = -1;
        }
    }
    
    

    钱包工具

    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.tld.admin.common.utils.SecureRandomUtils;
    import lombok.Data;
    import lombok.experimental.Accessors;
    import org.apache.commons.lang3.ObjectUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.web3j.crypto.*;
    import org.web3j.utils.Numeric;
    
    import java.io.File;
    import java.io.IOException;
    import java.math.BigInteger;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.util.Random;
    
    /**
     * 基于web3j的钱包工具类
     *
     * @author ming
     * @version 1.0.0
     * @date 2020/9/21 10:30
     **/
    public class Web3jWalletUtils {
    
        private Logger log = LoggerFactory.getLogger(this.getClass());
    
        private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
        private static final SecureRandom SECURE_RANDOM = SecureRandomUtils.secureRandom();
    
        static {
            // 转换为格式化的json
            OBJECT_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
            // 如果json中有新增的字段并且是实体类类中不存在的,不报错
            OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }
    
        public Web3jWalletUtils() {
    
        }
    
        /**
         * 创建普通钱包
         *
         * @param password       钱包密码
         * @param walletFilePath 钱包文件存储路径
         * @return CommonWallet
         * @throws Exception e
         */
        public CommonWallet generateCommonWallet(String password, String walletFilePath) throws Exception {
            try {
                String walletFileName = WalletUtils.generateNewWalletFile(password, new File(walletFilePath), false);
                String path = StringUtils.isNotBlank(walletFilePath) && File.separator.equals(walletFilePath.substring(walletFilePath.length() - 1)) ? walletFilePath + walletFileName : walletFilePath + File.separator + walletFileName;
                Credentials credentials = WalletUtils.loadCredentials(password, walletFilePath);
                String address = credentials.getAddress();
                BigInteger publicKey = credentials.getEcKeyPair().getPublicKey();
                BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey();
                return new CommonWallet(address, password, privateKey, publicKey, path);
            } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException | CipherException | IOException e) {
                throw new Exception(e);
            }
        }
    
        /**
         * 创建普通钱包
         *
         * @param password 密码
         * @return CommonWallet
         * @throws Exception e
         */
        public CommonWallet generateCommonWallet(String password) throws Exception {
            try {
                ECKeyPair ecKeyPair = Keys.createEcKeyPair();
                WalletFile walletFile = generateWalletFile(password, ecKeyPair, false);
                BigInteger publicKey = ecKeyPair.getPublicKey();
                BigInteger privateKey = ecKeyPair.getPrivateKey();
                return new CommonWallet(walletFile.getAddress(), JSON.toJSONString(walletFile), password, privateKey, publicKey);
            } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException | CipherException e) {
                throw new Exception(e);
            }
        }
    
        /**
         * 从钱包json加载钱包
         *
         * @param password 钱包密码
         * @param json     钱包json
         * @return CommonWallet
         * @throws JsonProcessingException jsonProcessingException
         * @throws CipherException         cipherException
         */
        public CommonWallet loadCommonWalletFromJson(String password, String json) throws JsonProcessingException, CipherException {
            WalletFile walletFile = OBJECT_MAPPER.readValue(json, WalletFile.class);
            log.debug("获取到的钱包Json: " + JSON.toJSONString(walletFile));
            Credentials credentials = loadCredentials(password, walletFile);
            String address = credentials.getAddress();
            ECKeyPair ecKeyPair = credentials.getEcKeyPair();
            BigInteger privateKey = ecKeyPair.getPrivateKey();
            BigInteger publicKey = ecKeyPair.getPublicKey();
            return new CommonWallet(address, json, password, privateKey, publicKey);
        }
    
        /**
         * 从钱包文件加载钱包
         *
         * @param password       密码
         * @param walletFilePath 钱包文件路径
         * @return CommonWallet
         * @throws IOException     e
         * @throws CipherException e
         */
        public CommonWallet loadCommonWalletFromFile(String password, String walletFilePath) throws IOException, CipherException {
            Credentials credentials = WalletUtils.loadCredentials(password, walletFilePath);
            String address = credentials.getAddress();
            ECKeyPair ecKeyPair = credentials.getEcKeyPair();
            BigInteger privateKey = ecKeyPair.getPrivateKey();
            BigInteger publicKey = ecKeyPair.getPublicKey();
            return new CommonWallet(address, password, privateKey, publicKey, walletFilePath);
        }
    
        /**
         * 创建bip39钱包
         *
         * @param password 钱包密码
         * @return CommonWallet
         * @throws CipherException e
         */
        public Bip39Wallet2 generateBip39Wallet(String password) throws CipherException {
            byte[] initialEntropy = new byte[16];
            SECURE_RANDOM.nextBytes(initialEntropy);
            String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy);
            byte[] seed = MnemonicUtils.generateSeed(mnemonic, password);
            ECKeyPair ecKeyPair = ECKeyPair.create(Hash.sha256(seed));
            WalletFile walletFile = generateWalletFile(password, ecKeyPair, false);
            return new Bip39Wallet2(walletFile.getAddress(), mnemonic, password, JSON.toJSONString(walletFile), ecKeyPair.getPrivateKey(), ecKeyPair.getPublicKey());
        }
    
        /**
         * 从json加载bip39钱包
         *
         * @param password 密码
         * @param mnemonic 助记词
         * @param json     钱包文件
         * @return Bip39Wallet2
         */
        public Bip39Wallet2 loadBip39WalletFromJson(String password, String mnemonic, String json) {
            Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);
            return new Bip39Wallet2(credentials.getAddress(), json, mnemonic, password, credentials.getEcKeyPair().getPrivateKey(), credentials.getEcKeyPair().getPublicKey());
        }
    
        /**
         * 从文件加载bip39钱包
         *
         * @param password       密码
         * @param mnemonic       助记词
         * @param walletFilePath 钱包文件
         * @return Bip39Wallet2
         */
        public Bip39Wallet2 loadBip39WalletFromFile(String password, String mnemonic, String walletFilePath) {
            Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);
            return new Bip39Wallet2(credentials.getAddress(), mnemonic, password, credentials.getEcKeyPair().getPrivateKey(), credentials.getEcKeyPair().getPublicKey(), walletFilePath);
        }
    
        /**
         * 创建bip39钱包
         *
         * @param password       钱包密码
         * @param walletFilePath 钱包文件路径
         * @return CommonWallet
         * @throws CipherException e
         */
        public Bip39Wallet2 generateBip39Wallet(String password, String walletFilePath) throws CipherException, IOException {
            Bip39Wallet bip39Wallet = WalletUtils.generateBip39Wallet(password, new File(walletFilePath));
            String mnemonic = bip39Wallet.getMnemonic();
            // 返回钱包文件名
            String filename = bip39Wallet.getFilename();
            Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);
            String address = credentials.getAddress();
            BigInteger publicKey = credentials.getEcKeyPair().getPublicKey();
            BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey();
            String path = StringUtils.isNotBlank(walletFilePath) && File.separator.equals(walletFilePath.substring(walletFilePath.length() - 1)) ? walletFilePath + filename : walletFilePath + File.separator + filename;
            return new Bip39Wallet2(address, mnemonic, password, privateKey, publicKey, path);
        }
    
        public static Credentials loadCredentials(String password, WalletFile walletFile) throws CipherException {
            return Credentials.create(Wallet.decrypt(password, walletFile));
        }
    
        public static WalletFile generateWalletFile(String password, ECKeyPair ecKeyPair, boolean useFullScrypt) throws CipherException {
            WalletFile walletFile;
            if (useFullScrypt) {
                walletFile = Wallet.createStandard(password, ecKeyPair);
            } else {
                walletFile = Wallet.createLight(password, ecKeyPair);
            }
            return walletFile;
        }
    
        public String signTransaction(String json, ECKeyPair keyPair) {
            Sign.SignatureData signatureData = Sign.signMessage(json.getBytes(), keyPair);
            JSONObject signatureDataJson = new JSONObject();
            signatureDataJson.put("v", Byte.toString(signatureData.getV()));
            signatureDataJson.put("r", Numeric.toBigInt(signatureData.getR()));
            signatureDataJson.put("s", Numeric.toBigInt(signatureData.getS()));
            return signatureDataJson.toJSONString();
        }
    
        /**
         * verify data
         * get public key and get wallet address with sign
         *
         * @param data          明文数据
         * @param walletAddress 钱包地址
         * @param strSign       签名数据
         * @return boolean
         * @throws Exception e
         */
        public boolean verifyTransaction(String data, String walletAddress, String strSign) throws Exception {
            try {
                if (StringUtils.isBlank(data)) {
                    return false;
                }
    
                JSONObject jsonSign = JSONObject.parseObject(strSign);
                if (jsonSign == null) {
                    return false;
                }
    
                byte v = jsonSign.getByte("v");
                byte[] r = Numeric.toBytesPadded(jsonSign.getBigInteger("r"), 32);
                byte[] s = Numeric.toBytesPadded(jsonSign.getBigInteger("s"), 32);
    
                Sign.SignatureData signatureData = new Sign.SignatureData(v, r, s);
    
                BigInteger publicKey = Sign.signedMessageToKey(data.getBytes(), signatureData);
                return StringUtils.equalsIgnoreCase("0x" + Keys.getAddress(publicKey), walletAddress);
            } catch (Exception e) {
                e.printStackTrace();
                throw new Exception(e);
            }
        }
    
        public String generateRandomPassword() {
            return generateRandomPassword(8);
        }
    
        public String generateRandomPassword(Integer count) {
            if (ObjectUtils.isEmpty(count)) {
                throw new RuntimeException("count must setting");
            }
            StringBuilder codeNum = new StringBuilder();
            int[] code = new int[3];
            Random random = new Random();
            for (int i = 0; i < count; i++) {
                int num = random.nextInt(10) + 48;
                int uppercase = random.nextInt(26) + 65;
                int lowercase = random.nextInt(26) + 97;
                code[0] = num;
                code[1] = uppercase;
                code[2] = lowercase;
                codeNum.append((char) code[random.nextInt(3)]);
            }
            return codeNum.toString();
        }
    
        @Data
        @Accessors(chain = true)
        static class CommonWallet {
            private String address;
            private String json;
            private String password;
            private BigInteger privateKey;
            private String privateKeyHexStr;
            private BigInteger publicKey;
            private String publicKeyHexStr;
            private String path;
    
            public CommonWallet(String address, String json, String password, BigInteger privateKey, BigInteger publicKey) {
                this.address = address;
                this.json = json;
                this.password = password;
                this.privateKey = privateKey;
                this.publicKey = publicKey;
                this.path = "";
                this.setPrivateKeyHexStr(privateKey);
                this.setPublicKeyHexStr(publicKey);
            }
    
            public CommonWallet(String address, String password, BigInteger privateKey, BigInteger publicKey, String path) {
                this.address = address;
                this.json = "";
                this.password = password;
                this.privateKey = privateKey;
                this.publicKey = publicKey;
                this.path = path;
                this.setPrivateKeyHexStr(privateKey);
                this.setPublicKeyHexStr(publicKey);
            }
    
            public void setPrivateKeyHexStr(BigInteger privateKey) {
                this.privateKeyHexStr = Numeric.toHexStringWithPrefix(privateKey);
            }
    
            public void setPublicKeyHexStr(BigInteger publicKey) {
                this.publicKeyHexStr = Numeric.toHexStringWithPrefix(publicKey);
            }
    
        }
    
        @Data
        @Accessors(chain = true)
        static class Bip39Wallet2 {
            private String address;
            private String password;
            private String json;
            private BigInteger privateKey;
            private String privateKeyHexStr;
            private BigInteger publicKey;
            private String publicKeyHexStr;
            private String mnemonic;
            private String path;
    
            public Bip39Wallet2(String address, String mnemonic, String password, String json, BigInteger privateKey, BigInteger publicKey) {
                this.address = address;
                this.password = password;
                this.json = json;
                this.privateKey = privateKey;
                this.publicKey = publicKey;
                this.mnemonic = mnemonic;
                this.path = "";
                this.setPrivateKeyHexStr(privateKey);
                this.setPublicKeyHexStr(publicKey);
            }
    
            public Bip39Wallet2(String address, String mnemonic, String password, BigInteger privateKey, BigInteger publicKey, String path) {
                this.address = address;
                this.password = password;
                this.json = "";
                this.privateKey = privateKey;
                this.publicKey = publicKey;
                this.mnemonic = mnemonic;
                this.path = path;
                this.setPrivateKeyHexStr(privateKey);
                this.setPublicKeyHexStr(publicKey);
            }
    
    
            public void setPrivateKeyHexStr(BigInteger privateKey) {
                this.privateKeyHexStr = Numeric.toHexStringWithPrefix(privateKey);
            }
    
            public void setPublicKeyHexStr(BigInteger publicKey) {
                this.publicKeyHexStr = Numeric.toHexStringWithPrefix(publicKey);
            }
        }
    }
    

    测试方法

    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.web3j.crypto.CipherException;
    import org.web3j.crypto.Credentials;
    import org.web3j.crypto.WalletUtils;
    
    import java.io.IOException;
    
    
    class Web3jWalletUtilsTest {
        private Logger log = LoggerFactory.getLogger(this.getClass());
        private static Web3jWalletUtils web3jWalletUtils;
    
        private static final String COMMON_WALLET_PATH = "E:\tmp\wallet_home\common_wallet";
        private static final String BIP39_WALLET_PATH = "E:\tmp\wallet_home\bip39_wallet";
    
        @BeforeEach
        void setUp() {
            web3jWalletUtils = new Web3jWalletUtils();
        }
    
        /**
         * 普通钱包生成和恢复 -- json
         *
         * @throws Exception e
         */
        @Test
        void generateCommonWalletTest() throws Exception {
            Web3jWalletUtils.CommonWallet commonWallet = web3jWalletUtils.generateCommonWallet("");
            log.debug(JSON.toJSONString(commonWallet));
            // 从json加载
            Web3jWalletUtils.CommonWallet commonWallet1 = web3jWalletUtils.loadCommonWalletFromJson("", commonWallet.getJson());
            log.debug("加载的json: " + commonWallet1.getJson());
        }
    
        /**
         * 普通钱包生成和恢复 -- file
         *
         * @throws Exception e
         */
        @Test
        void generateCommonWalletOnWalletPathTest() throws Exception {
            Web3jWalletUtils.CommonWallet commonWallet = web3jWalletUtils.generateCommonWallet("", COMMON_WALLET_PATH);
            log.debug("生成的普通钱包: " + JSON.toJSONString(commonWallet));
            // 从文件加载
            Web3jWalletUtils.CommonWallet commonWallet1 = web3jWalletUtils.loadCommonWalletFromFile("", commonWallet.getPath());
            log.debug("从文件加载的json: " + commonWallet1.getJson());
        }
    
        /**
         * bip39钱包生成和恢复 -- json
         *
         * @throws CipherException e
         */
        @Test
        void bip39Wallet2Test() throws CipherException {
            Web3jWalletUtils.Bip39Wallet2 bip39Wallet2 = web3jWalletUtils.generateBip39Wallet("");
            log.debug("生成的bip39钱包: " + JSON.toJSONString(bip39Wallet2));
            // 从json加载钱包
            Web3jWalletUtils.Bip39Wallet2 bip39Wallet21 = web3jWalletUtils.loadBip39WalletFromJson("", bip39Wallet2.getMnemonic(), bip39Wallet2.getJson());
            log.debug("从json加载的bip39钱包: " + JSON.toJSONString(bip39Wallet21));
        }
    
        /**
         * bip39钱包生成和恢复 -- file
         *
         * @throws CipherException e
         * @throws IOException     e
         */
        @Test
        void bip39Wallet2OnWalletPathTest() throws CipherException, IOException {
            Web3jWalletUtils.Bip39Wallet2 bip39Wallet2 = web3jWalletUtils.generateBip39Wallet("", BIP39_WALLET_PATH);
            log.debug("生成的bip39钱包" + JSON.toJSONString(bip39Wallet2));
            Web3jWalletUtils.Bip39Wallet2 bip39Wallet21 = web3jWalletUtils.loadBip39WalletFromFile("", bip39Wallet2.getMnemonic(), bip39Wallet2.getPath());
            log.debug("生成的bip39钱包" + JSON.toJSONString(bip39Wallet21));
        }
    
        /**
         * 生成随机密码
         */
        @Test
        void generateRandomPasswordTest() {
            log.debug(web3jWalletUtils.generateRandomPassword());
            log.debug(web3jWalletUtils.generateRandomPassword(16));
        }
    
        /**
         * bip39钱包签名和验证交易
         */
        @Test
        void bip39WalletSignAndVerifyTransaction() throws Exception {
            // TODO: 2020/9/24 生成bip39钱包
            Web3jWalletUtils.Bip39Wallet2 bip39Wallet2 = web3jWalletUtils.generateBip39Wallet("123456", BIP39_WALLET_PATH);
            log.debug("生成的bip39钱包" + JSON.toJSONString(bip39Wallet2));
            String password = bip39Wallet2.getPassword();
            String mnemonic = bip39Wallet2.getMnemonic();
            log.debug("钱包密码: " + password);
            log.debug("钱包助记词: " + mnemonic);
    
            // TODO: 2020/9/24 获取原始数据
            JSONObject data = new JSONObject();
            data.put("fromWalletAddress", bip39Wallet2.getAddress());
            data.put("toWalletAddress", "0x565fe768c659259abn45cf4f1081a663d091bcb9");
            data.put("value", "99.4");
            data.put("chargeWalletAddress", "0xdd05e23c39eead942bcv63fd388ffa13a1a28307");
            data.put("chargeValue", "0.6");
            String rawData = data.toJSONString();
            log.debug("原始数据 : " + rawData);
    
            Credentials credentials = WalletUtils.loadBip39Credentials(password, mnemonic);
            // TODO: 2020/9/24 对原始数据进行签名
            String sign = web3jWalletUtils.signTransaction(rawData, credentials.getEcKeyPair());
            // TODO: 2020/9/24 验证签名的数据
            boolean flag = web3jWalletUtils.verifyTransaction(rawData, bip39Wallet2.getAddress(), sign);
            log.debug("验签结果: " + flag);
        }
    
    }
    
  • 相关阅读:
    CMake 手册详解(十九)
    CMake 手册详解(二十三)
    CMake 手册详解(二十)
    xtrabackupex xbstream 流备份还原(转载)
    xtrabackup 安装与使用(转载)
    怎么样写好一篇技术博客
    python为什么需要符号表
    cmake的一些基本概念及源码结构
    让IT工作者过劳的13个坏习惯
    SHTML和HTML的区别
  • 原文地址:https://www.cnblogs.com/jockming/p/13725576.html
Copyright © 2020-2023  润新知