一个单例的错误用法引发的思考

服务器这边使用了加密接口,发现接口很多无法解密的数据,进行排查后发现客户端的加密数据是错误的,猜测是秘钥使用错误。

验证后果然是。

和客户端一起排查,发现加密类 实例化一次后,又来了一次传参数的实例化 里面设置了加密类型instance.setDesType(type),导致接口的加密串掉。

 private byte[] desKey = desDefaultKey;

    private static final String DEFAULT_KEY_ALGORITHM = "DES";

    private static CryptoUtils instance;

    public static CryptoUtils getInstance(int type) {
        if (instance == null) {
            synchronized (CryptoUtils.class) {
                if (instance == null) {
                    instance = new CryptoUtils();
                }
            }
        }
        instance.setDesType(type);//<<<<<<<********
        return instance;
    }

    public static CryptoUtils getInstance() {
        if (instance == null) {
            synchronized (CryptoUtils.class) {
                if (instance == null) {
                    instance = new CryptoUtils();
                }
            }
        }
        return instance;
    }
private void setDesType(int type) {

        switch (type) {

            case TYPE_ACCOUNT:
                desKey = desAccountKey;
                break;

            case TYPE_DEFAULT:
            default:
                desKey = desDefaultKey;
                break;

        }
    }
.....

 

修改的建议,加密类的实例化最好就是一个单一的功能,通过闯入秘钥的方式来解决问题。

修改的是变成


public class CryptoUtils {


    private byte[] desDefaultKey = new byte[]{};
    private byte[] desAccountKey = new byte[]{};
    private byte[] desUploadLogKey = new byte[]{};

    private byte[] desKey = desDefaultKey;

    private static final String DEFAULT_KEY_ALGORITHM = "DES";

    private static CryptoUtils instance;

    public static CryptoUtils getInstance(int type) {
        if (instance == null) {
            synchronized (CryptoUtils.class) {
                if (instance == null) {
                    instance = new CryptoUtils();
                }
            }
        }
        instance.setDesType(type);
        return instance;
    }

    public static CryptoUtils getInstance() {
        if (instance == null) {
            synchronized (CryptoUtils.class) {
                if (instance == null) {
                    instance = new CryptoUtils();
                }
            }
        }
        return instance;
    }


    public static final int TYPE_DEFAULT = 0;
    public static final int TYPE_ACCOUNT = 1;
    public static final int TYPE_DOWNLOAD = 2;
    public static final int TYPE_UPLOAD_LOG = 3;

    private void setDesType(int type) {

        switch (type) {

            case TYPE_ACCOUNT:
                desKey = desAccountKey;
                break;
            case TYPE_UPLOAD_LOG:
                desKey = desUploadLogKey;
                break;
            case TYPE_DEFAULT:
            default:
                desKey = desDefaultKey;
                break;

        }
    }


    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }

    /**
     * byte[] 转16进制
     */
    public static String bytesToHexFun(byte[] encryptedData) {
        StringBuilder buf = new StringBuilder(encryptedData.length * 2);
        // 使用String的format方法进行转换
        for (byte b : encryptedData) {
            buf.append(String.format("%02x", b & 0xff));
        }
        return buf.toString();
    }

    /**
     * 加密
     */
    public byte[] encrypy(byte[] input) {

    }

    /**
     * 解密
     */
    public String decrypt(byte[] input) throws Exception {

       
        return new String(numArray);

    }

    public static SecretKey getSecretKey(byte[] key) throws Exception {

      
    }

    private String toMd5(byte[] bytes) {
        try {
            MessageDigest algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(bytes);
            return toHexString(algorithm.digest(), "");
        } catch (NoSuchAlgorithmException e) {
            Log.v("toMd5", "toMd5(): " + e);
            throw new RuntimeException(e);
        }
    }

    private String toHexString(byte[] bytes, String separator) {
        StringBuilder hexString = new StringBuilder();
        String hs;
        for (byte b : bytes) {
            hs = Integer.toHexString(0xFF & b);
            if (hs.length() == 1) {
                hexString.append("0").append(hs);
            } else {
                hexString.append(hs);
            }
            hexString.append(separator);
        }
        return hexString.toString();
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单例模式是一种常见的设计模式,它确保一个类只能创建一个对象,并提供对该对象的全局访问点。在Java中,实现单例模式可以采用以下方式: 1. 饿汉式单例模式 ```java public class Singleton { // 创建一个Singleton对象,使用private static final修饰,确保只有一个实例 private static final Singleton instance = new Singleton(); // 构造函数私有化,禁止外部实例化对象 private Singleton() {} // 提供静态方法返回Singleton实例 public static Singleton getInstance() { return instance; } } ``` 2. 懒汉式单例模式 ```java public class Singleton { // 创建一个Singleton对象,但不进行初始化 private static Singleton instance; // 构造函数私有化,禁止外部实例化对象 private Singleton() {} // 提供静态方法返回Singleton实例,当instance为null时进行初始化 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` 以上两种方式都是线程安全的。如果需要保证线程安全,可以将getInstance()方法加上synchronized关键字。 3. 双重校验锁单例模式 ```java public class Singleton { // 创建一个volatile修饰的Singleton对象,确保线程可见性 private static volatile Singleton instance; // 构造函数私有化,禁止外部实例化对象 private Singleton() {} // 提供静态方法返回Singleton实例,使用双重校验锁确保线程安全 public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 以上三种方式都可以实现单例模式,选择哪一种方式取决于实际需要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值