All Downloads are FREE. Search and download functionalities are using the official Maven repository.

network.nerve.kit.model.Account Maven / Gradle / Ivy

There is a newer version: 1.2.5
Show newest version
/*
 * MIT License
 *
 * Copyright (c) 2017-2018 nuls.io
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package network.nerve.kit.model;

import network.nerve.base.data.Address;
import network.nerve.core.crypto.AESEncrypt;
import network.nerve.core.crypto.ECKey;
import network.nerve.core.crypto.EncryptedData;
import network.nerve.core.crypto.Sha256Hash;
import network.nerve.core.exception.CryptoException;
import network.nerve.core.exception.NulsException;
import network.nerve.core.model.FormatValidUtils;
import network.nerve.core.model.ObjectUtils;
import network.nerve.kit.error.AccountErrorCode;
import org.bouncycastle.crypto.params.KeyParameter;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.Arrays;

/**
 * @author: qinyifeng
 */
public class Account implements Serializable {


    /**
     * chain id
     */
    private int chainId;

    /**
     * 账户地址
     */

    private transient Address address;

    /**
     * 账户别名
     */

    private String alias;

    /**
     * is default acct
     */

    private int status;

    /**
     * 账户公钥
     */

    private byte[] pubKey;

    /**
     * 扩展字段
     */

    private byte[] extend;

    /**
     * 创建时间
     */

    private Long createTime;


    private byte[] encryptedPriKey;

    /**
     * Decrypted  prikey
     */

    private byte[] priKey;

    /**
     * local field
     */

    private transient ECKey ecKey;


    private String remark;


    /**
     * 账户是否被加密(是否设置过密码)
     * Whether the account is encrypted (Whether the password is set)
     */
    public boolean isEncrypted() {
        return getEncryptedPriKey() != null && getEncryptedPriKey().length > 0;
    }

    /**
     * 锁定账户
     * Lock account
     */
    public void lock() {
        if (!isEncrypted()) {
            return;
        }

        if (this.getEcKey().getEncryptedPrivateKey() != null) {
            ECKey result = ECKey.fromEncrypted(getEcKey().getEncryptedPrivateKey(), getPubKey());
            this.setPriKey(new byte[0]);
            this.setEcKey(result);
        }
    }

    public byte[] getHash160() {
        return this.getAddress().getHash160();
    }

    /**
     * 根据密码解锁账户
     * Unlock account based on password
     */
    public boolean unlock(String password) throws NulsException {
        decrypt(password);
        return !isLocked();
    }

    /**
     * 账户是否被锁定(是否有明文私钥) 有私钥表示解锁
     * Whether the account is locked (is there a cleartext private key)
     *
     * @return true: Locked, false: not Locked
     */
    public boolean isLocked() {
        return (this.getPriKey() == null) || (this.getPriKey().length == 0);
    }

    /**
     * 验证账户密码是否正确
     * Verify that the account password is correct
     */
    public boolean validatePassword(String password) {
        boolean result = FormatValidUtils.validPassword(password);
        if (!result) {
            return false;
        }
        byte[] unencryptedPrivateKey;
        try {
            unencryptedPrivateKey = AESEncrypt.decrypt(this.getEncryptedPriKey(), password);
        } catch (CryptoException e) {
            return false;
        }
        BigInteger newPriv = new BigInteger(1, unencryptedPrivateKey);
        ECKey key = ECKey.fromPrivate(newPriv);

        return Arrays.equals(key.getPubKey(), getPubKey());
    }

    /**
     * 根据密码加密账户(给账户设置密码)
     * Password-encrypted account (set password for account)
     */
    public void encrypt(String password) throws NulsException {
        encrypt(password, false);
    }

    /**
     * 根据密码加密账户(给账户设置密码)
     * Password-encrypted account (set password for account)
     */
    public void encrypt(String password, boolean isForce) throws NulsException {
        if (this.isEncrypted()) {
            if (isForce) {
                if (isLocked()) {
                    throw new NulsException(AccountErrorCode.ACCOUNT_IS_ALREADY_ENCRYPTED_AND_LOCKED);
                }
            } else {
                throw new NulsException(AccountErrorCode.ACCOUNT_IS_ALREADY_ENCRYPTED);
            }
        }
        ECKey eckey = this.getEcKey();
        byte[] privKeyBytes = eckey.getPrivKeyBytes();
        EncryptedData encryptedPrivateKey = AESEncrypt.encrypt(privKeyBytes, EncryptedData.DEFAULT_IV, new KeyParameter(Sha256Hash.hash(password.getBytes())));
        eckey.setEncryptedPrivateKey(encryptedPrivateKey);
        ECKey result = ECKey.fromEncrypted(encryptedPrivateKey, getPubKey());
        this.setPriKey(new byte[0]);
        this.setEcKey(result);
        this.setEncryptedPriKey(encryptedPrivateKey.getEncryptedBytes());
    }

    /**
     * 根据解密账户, 包括生成账户明文私钥
     * According to the decryption account, including generating the account plaintext private key
     */
    private boolean decrypt(String password) throws NulsException {
        try {
            byte[] unencryptedPrivateKey = AESEncrypt.decrypt(this.getEncryptedPriKey(), password);
            BigInteger newPriv = new BigInteger(1, unencryptedPrivateKey);
            ECKey key = ECKey.fromPrivate(newPriv);

            if (!Arrays.equals(key.getPubKey(), getPubKey())) {
                return false;
            }
            key.setEncryptedPrivateKey(new EncryptedData(this.getEncryptedPriKey()));
            this.setPriKey(key.getPrivKeyBytes());
            this.setEcKey(key);
        } catch (Exception e) {
            throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
        }
        return true;
    }

    public Object copy() {
        Account account = new Account();
        account.setChainId(chainId);
        account.setAlias(alias);
        account.setAddress(address);
        account.setStatus(status);
        account.setPubKey(pubKey);
        account.setExtend(extend);
        account.setCreateTime(createTime);
        account.setEncryptedPriKey(encryptedPriKey);
        account.setPriKey(priKey);
        account.setEcKey(ecKey);
        account.setRemark(remark);
        return account;
    }

    public int getChainId() {
        return chainId;
    }

    public void setChainId(int chainId) {
        this.chainId = chainId;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public byte[] getPubKey() {
        return pubKey;
    }

    public void setPubKey(byte[] pubKey) {
        this.pubKey = pubKey;
    }

    public byte[] getExtend() {
        return extend;
    }

    public void setExtend(byte[] extend) {
        this.extend = extend;
    }

    public Long getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Long createTime) {
        this.createTime = createTime;
    }

    public byte[] getEncryptedPriKey() {
        return encryptedPriKey;
    }

    public void setEncryptedPriKey(byte[] encryptedPriKey) {
        this.encryptedPriKey = encryptedPriKey;
    }

    public byte[] getPriKey() {
        return priKey;
    }

    public byte[] getPriKey(String password) throws NulsException {
        if (!FormatValidUtils.validPassword(password)) {
            throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
        }
        byte[] unencryptedPrivateKey;
        try {
            unencryptedPrivateKey = AESEncrypt.decrypt(this.getEncryptedPriKey(), password);
        } catch (CryptoException e) {
            throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
        }
        BigInteger newPriv = new BigInteger(1, unencryptedPrivateKey);
        ECKey key = ECKey.fromPrivate(newPriv);

        if (!Arrays.equals(key.getPubKey(), getPubKey())) {
            throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
        }
        return unencryptedPrivateKey;
    }

    public void setPriKey(byte[] priKey) {
        this.priKey = priKey;
    }

    public ECKey getEcKey() {
        return ecKey;
    }

    public void setEcKey(ECKey ecKey) {
        this.ecKey = ecKey;
    }

    /**
     * 根据密码获取ECKey
     */
    public ECKey getEcKey(String password) throws NulsException {
        ECKey eckey = null;
        byte[] unencryptedPrivateKey;
        //判断当前账户是否存在私钥,如果不存在私钥这为加密账户
        BigInteger newPriv = null;
        if (this.isEncrypted()) {
            ObjectUtils.canNotEmpty(password, "the password can not be empty");
            if (!validatePassword(password)) {
                throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
            }
            try {
                unencryptedPrivateKey = AESEncrypt.decrypt(this.getEncryptedPriKey(), password);
                newPriv = new BigInteger(1, unencryptedPrivateKey);
            } catch (CryptoException e) {
                throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
            }
        } else {
            newPriv = new BigInteger(1, this.getPriKey());
        }
        eckey = ECKey.fromPrivate(newPriv);
        if (!Arrays.equals(eckey.getPubKey(), getPubKey())) {
            throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
        }
        return eckey;
    }

    public ECKey getEcKey1(String password) throws NulsException {
        ECKey eckey = null;
        byte[] unencryptedPrivateKey;
        //判断当前账户是否存在私钥,如果不存在私钥这为加密账户
        BigInteger newPriv = null;
        if (this.isEncrypted()) {
            ObjectUtils.canNotEmpty(password, "the password can not be empty");
            if (!validatePassword(password)) {
                throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
            }
            try {
                unencryptedPrivateKey = AESEncrypt.decrypt(this.getEncryptedPriKey(), password);
                newPriv = new BigInteger(unencryptedPrivateKey);
            } catch (CryptoException e) {
                throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
            }
        } else {
            newPriv = new BigInteger(this.getPriKey());
        }
        eckey = ECKey.fromPrivate(newPriv);
        if (!Arrays.equals(eckey.getPubKey(), getPubKey())) {
            throw new NulsException(AccountErrorCode.PASSWORD_IS_WRONG);
        }
        return eckey;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Account)) {
            return false;
        }
        Account other = (Account) obj;
        return Arrays.equals(pubKey, other.getPubKey());
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(pubKey);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy