接入数盾OTP

zhuc 2025-02-17 4298 阅读

为了数字化系统应用的安全,迎合政府需求。

数盾OTP支持合法合规的密码应用,符合国家密码主管部门对商用密码的应用要求。同时,通过可视化展示和密码服务监管,能够有效支持安全决策

通过动态密码技术,数盾OTP能够有效降低因密码泄露而导致的安全风险,同时支持多种安全策略,如限制输入错误次数、设置有效期等。


具体流程

1、在首次登录时根据用户的账号和平台名称扫码绑定令牌 或是 在注册时进行扫码绑定

2、下次登录时根据账号,密码,数盾验证码进行登陆验证




pom中引入


<dependency>
   <groupId>com.google.zxing</groupId>
   <artifactId>core</artifactId>
   <version>3.4.1</version>
</dependency>
<dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>31.0.1-jre</version>
</dependency>


java方法


import com.google.common.io.BaseEncoding;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;


import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;

import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import java.util.HashMap;
import java.util.Map;

public class TOTPGenerator {

    // 生成TOTP密钥
    public static String generateSecretKey(int keySize) {
        SecureRandom random = new SecureRandom();
        byte[] key = new byte[keySize];
        random.nextBytes(key);
        return BaseEncoding.base32().encode(key); // 使用Base32编码
    }

    // 生成TOTP URI
    public static String generateTOTPURI(String secretKey, String issuer, String accountName) {
        return String.format("otpauth://totp/%s:%s?secret=%s&issuer=%s",
                issuer, accountName, secretKey, issuer);
    }

    // 生成二维码
    public static void generateQRCode(String otpUri, String filePath, int width, int height) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        Map<EncodeHintType, String> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        BitMatrix bitMatrix = qrCodeWriter.encode(otpUri, BarcodeFormat.QR_CODE, width, height, hints);
        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
    }

    // 生成6位OTP密码
    public static String generateOTP(String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
        long currentTime = System.currentTimeMillis() / 1000; // 当前时间(秒)
        long timeStep = currentTime / 30; // TOTP时间步长为30秒

        byte[] timeStepBytes = longToBytes(timeStep);

        Mac mac = Mac.getInstance("HmacSHA1");
        byte[] secretKeyBytes = BaseEncoding.base32().decode(secretKey);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA1");
        mac.init(secretKeySpec);

        byte[] hash = mac.doFinal(timeStepBytes);

        int offset = hash[hash.length - 1] & 0xf;
        int truncatedHash = hashToInt(hash, offset) & 0x7FFFFFFF;
        int otp = truncatedHash % 1000000; // 生成6位动态口令
        return String.format("%06d", otp); // 格式化为6位字符串
    }

    // 辅助方法:将长整型转换为字节数组
    private static byte[] longToBytes(long value) {
        byte[] bytes = new byte[8];
        for (int i = 0; i < 8; i++) {
            bytes[i] = (byte) (value >>> (56 - i * 8));
        }
        return bytes;
    }

    // 辅助方法:将字节数组转换为整数
    private static int hashToInt(byte[] hash, int offset) {
        return ((hash[offset] & 0xFF) << 24) |
                ((hash[offset + 1] & 0xFF) << 16) |
                ((hash[offset + 2] & 0xFF) << 8) |
                (hash[offset + 3] & 0xFF);
    }

    public static void main(String[] args) {
        try {
             //生成密钥
            String secretKey = generateSecretKey(10); // 生成10字节的密钥
            System.out.println("Generated Secret Key: " + secretKey);

            // 生成TOTP URI
            String issuer = "issuer";
            String accountName = "accountName";
            String otpUri = generateTOTPURI(secretKey, issuer, accountName);
            System.out.println("Generated OTP URI: " + otpUri);

            // 生成二维码并保存为PNG文件
            String filePath = "d://otp_qr_code.png";
            generateQRCode(otpUri, filePath, 300, 300);
            System.out.println("QR Code generated and saved to: " + filePath);
            
            // 生成6位OTP密码
            String otp = generateOTP(secretKey);
           System.out.println("Generated OTP: " + otp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}