您当前的位置: 首页 > 

命运之手

暂无认证

  • 5浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【ONVIF】ONVIF密码加密方式解析

命运之手 发布时间:2022-09-26 17:43:51 ,浏览量:5

什么是ONVIF

ONVIF是一个国际通用的摄像头通信控制协议,一般主流的设备厂商都支持该协议

为什么要写这篇博客

今天在实现android版本ONVIF协议时,发现它的加密方式,是一个很好的学习案例

所以特地总结一下,供大家学习,加密方式属于通用知识,不仅适用于摄像头,也适合与客户端、服务端等领域

ONVIF的通信流程

  1. 客户端通过Http向摄像头发送一个xml字符串,该xml中包含了随机数,用户名,当前时间,加密后的密码
  2. 摄像头判断随机数是否使用过,如果已使用过,直接请求失败
  3. 摄像头判断时间与当前差距是否很大,如果相隔很久,直接请求失败
  4. 摄像头通过客户端提供的信息,和真实密码,校验加密后的密码是否正确,校验失败则请求失败
  5. 以上流程都通过,并且内容格式正确,则请求成功

密码加密和校验原理

这里我们把摄像头当作服务端,因为它内置了一个Http服务

  1. 客户端将nonce+time+password相加,生成一个sha1摘要字符串,作为加密后的密码
  2. 服务端也按照一样的方式,生成sha1摘要,对比摘要是否相同,相同则说明密码正确
  3. 服务端将nonce标记为已使用,下次遇到相同的nonce,直接请求失败
  4. 服务端校验time和当前时间是否相隔很久,如果相隔很久,直接请求失败
  5. 由于sha1是摘要算法,不可逆,因此即使报文泄漏也无法抓取真实密码
  6. 由于nonce是一次性的,因此抓取到sha1,也无法再次复用
  7. 由于服务端有错误次数限制,也无法通过暴力方式破解

密码加密实现代码


	package com.wp.android_onvif.onvifBean;
	
	import java.security.MessageDigest;
	import java.text.SimpleDateFormat;
	import java.util.*;
	
	//加密过程:
	//客户端将nonce+time+password拼装起来,生成一个sha1摘要字符串,作为加密后的密码
	//加密过程:
	//服务端也按照一样的方式,生成sha1摘要,对比是否相等
	//并将该nonce标记为已使用过,不允许再次使用
	//安全性原理:
	//由于sha1是摘要算法,不可逆的,因此即使报文泄漏也无法抓取真实密码
	//由于nonce是一次性的,因此抓取到sha1,也无法再次复用
	//由于服务端有错误次数限制,也无法通过暴力方式破解
	public class Digest {
	
	    public String nonce;
	    public String username;
	    public String password;
	    public String time;
	
	    public String encryptedNonce;
	    public String encryptedPassword;
	
	    public static Digest build(String username, String password) throws Throwable {
	        Digest digest = new Digest();
	        digest.nonce = new Random().nextInt() + "";
	        digest.username = username;
	        digest.password = password;
	        digest.time = digest.getUTCTime();
	        digest.encryptedNonce = android.util.Base64.encodeToString(digest.nonce.getBytes(), android.util.Base64.DEFAULT).trim();
	        digest.encryptedPassword = digest.getEncryptedPassword().trim();
	        return digest;
	    }
	
	    protected String getUTCTime() {
	        Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
	        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss'Z'");
	        format.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
	        String utcTime = format.format(calendar.getTime());
	        return utcTime;
	    }
	
	    protected String getEncryptedPassword() throws Throwable {
	        String origin = nonce + time + password;
	        byte[] encrypted = sha1(origin);
	        String encoded = android.util.Base64.encodeToString(encrypted, android.util.Base64.DEFAULT);
	        return encoded;
	    }
	
	    protected byte[] sha1(String origin) throws Throwable {
	        MessageDigest SHA1 = MessageDigest.getInstance("SHA1");
	        SHA1.reset();
	        SHA1.update(origin.getBytes());
	        byte[] encrypted = SHA1.digest();
	        return encrypted;
	    }
	}



关注
打赏
1654938663
查看更多评论
立即登录/注册

微信扫码登录

0.0401s