zoukankan      html  css  js  c++  java
  • 一段JAVA签名算法的PHP改写

    源代码是这样的:

    public class AuthorizationSignature {
        public static String createSignature(String verb, String contentMD5, String contentType, String date,
                String canonicalizedSALHeaders, String canonicalizedResource) {
            String signatureStr = verb + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n"
                    + canonicalizedSALHeaders + canonicalizedResource;
            signatureStr = java.net.URLDecoder.decode(signatureStr);
            HmacSHA1Signature hss = new HmacSHA1Signature();
            String toSignature = hss.computeSignature(AuthConfiguration.getInstance().getAuthConfigurationDTO()
                    .getSecretKey(), signatureStr);
            String authorization = AuthConfiguration.getInstance().getAuthConfigurationDTO().getEnterpriseHeader()
                    + AuthConfiguration.getInstance().getAuthConfigurationDTO().getAccessKey() + ":" + toSignature;
            return authorization;
        }
    }
    

      

    public class HmacSHA1Signature extends ServiceSignature {
        private static final Logger LOG = LoggerFactory.getLogger(HmacSHA1Signature.class);
    
        private static final String DEFAULT_CHARSET = "UTF-8";
        private static final String ALGORITHM = "HmacSHA1";
    
        @Override
        public String getAlgorithm() {
            return ALGORITHM;
        }
    
        @Override
        public String computeSignature(String key, String data) {
            byte[] signData = null;
            try {
                signData = signature(key.getBytes(DEFAULT_CHARSET), data.getBytes(DEFAULT_CHARSET));
            } catch (UnsupportedEncodingException ex) {
                LOG.debug(ex.getMessage());
            }
            return BinaryUtil.toBase64String(signData);
        }
    
        private byte[] signature(byte[] key, byte[] data) {
            try {
                Mac mac = Mac.getInstance(ALGORITHM);
                mac.init(new SecretKeySpec(key, ALGORITHM));
                return mac.doFinal(data);
            } catch (NoSuchAlgorithmException e1) {
                // throw new RuntimeException("Unsupported algorithm: HmacSHA1");
                LOG.error("Unsupported algorithm: HmacSHA1", e1);
                return null;
            } catch (InvalidKeyException e) {
                // throw new RuntimeException();
                LOG.debug(e.getMessage());
                return null;
            }
        }
    }
    

      

    public class BinaryUtil {
        private static final Logger LOG = LoggerFactory.getLogger(BinaryUtil.class);
    
        public static String toBase64String(byte[] binaryData) {
            String toBase64Result = null;
            try {
                toBase64Result = new String(Base64.encodeBase64(binaryData), ContentUtil.BYTE_CODE);
            } catch (UnsupportedEncodingException e) {
                LOG.debug(e.getMessage());
            }
            return toBase64Result;
        }
    
        public static byte[] fromBase64String(String base64String) {
            byte[] fromBase64Result = null;
            try {
                fromBase64Result = Base64.decodeBase64(base64String.getBytes(ContentUtil.BYTE_CODE));
            } catch (UnsupportedEncodingException e) {
                LOG.debug(e.getMessage());
            }
            return fromBase64Result;
        }
    }
    

      需要改写为PHP代码, 一步步分析, 首先是核心的MAC_SHA1签名算法

                Mac mac = Mac.getInstance(ALGORITHM);
                mac.init(new SecretKeySpec(key, ALGORITHM));
                return mac.doFinal(data);
    

      等效的PHP代码是调用内建函数hash_hmac, JAVA代码是针对字节数组签名返回字节数组, 所以这里对返回值需要处理一下, 处理成字节数组

    <?php
    require_once DIR_SAL . 'util/BytesUtil.php';
    require_once DIR_SAL . 'util/Base64Util.php';
    class HmacSHA1Signature {
    
    	public function computeSignature($key, $data) {
    		$hash = $this->hmac ( $data, $key );
    		$hash = str_split ( $hash );
    		foreach ( $hash as $index => $value ) {
    			$asc = ord ( $value );
    			if ($asc > 128) {
    				$hash [$index] = ord ( $value ) - 128 * 2;
    			} else {
    				$hash [$index] = ord ( $value );
    			}
    		}
    		$bytes = Base64Util::encodeBase64($hash);
    		return BytesUtil::toStr($bytes);
    	}
    
    	private function hmac($data, $key, $hashFunc = 'sha1', $rawOutput = true) {
    		if (! in_array ( $hashFunc, hash_algos () )) {
    			$hashFunc = 'sha1';
    		}
    		return hash_hmac ( $hashFunc, $data, $key, $rawOutput );
    	}
    }
    

      JAVA代码中还将结果的字节数组进行base64转换

        public static String toBase64String(byte[] binaryData) {
            String toBase64Result = null;
            try {
                toBase64Result = new String(Base64.encodeBase64(binaryData), ContentUtil.BYTE_CODE);
            } catch (UnsupportedEncodingException e) {
                LOG.debug(e.getMessage());
            }
            return toBase64Result;
        }

    这个转码方式符合base64的定义, 即将3个8位表示数据的方式转变为4个6位标识数据, 即3*8=4*6, 这样会多出若干字节值, 具体算法实现通过bing搜到的2篇文章中的JAVA代码综合起来实现 (直接使用base64对字符串编码的结果和预期不符):

    <?php
    class Base64Util {
    
    	public static function encodeBase64($data) {
    		$encodes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    		require_once DIR_VENTOR . 'sal/util/BytesUtil.php';
    		$encodes = BytesUtil::getBytes_10 ( $encodes );
    		$dataLength = intval ( count ( $data ) );
    		$modulus = intval ( $dataLength % 3 );
    		//计算结果应有位数
    		if ($modulus == 0) {
    			//byte位数能被3整除
    			$sbLength = intval ( (4 * $dataLength) / 3 );
    		} else {
    			$sbLength = intval ( 4 * (intval ( ($dataLength / 3) ) + 1) );
    		}
    		$sb = array ();
    		$pos = 0;
    		$val = 0;
    		foreach ( $data as $i => $byte ) {
    			$val = ($val << 8) | ($data [$i] & 0xFF);
    			$pos += 8;
    			while ( $pos > 5 ) {
    				$index = $val >> ($pos -= 6);
    				$sb [] = $encodes [$index];
    				$val &= ((1 << $pos) - 1);
    			}
    		}
    		if ($pos > 0) {
    			$index = $val << (6 - $pos);
    			$sb [] = $encodes [$index];
    		}
    		//位数不够的用=字符(ascII值为61)填充
    		$real = count ( $sb );
    		if ($real < $sbLength) {
    			for($i = 0; $i < $sbLength - $real; $i ++) {
    				$sb [] = 61;
    			}
    		}
    		return $sb;
    	}
    }
    

      

  • 相关阅读:
    jQuery form插件的使用--处理server返回的JSON, XML,HTML数据
    jQuery form插件的使用--使用 fieldValue 方法校验表单
    jQuery form插件的使用--用 formData 参数校验表单,验证后提交(简单验证).
    jQuery form插件的使用--ajaxForm()和ajaxSubmit()的可选参数项对象
    jQuery Form 表单提交插件-----formSerialize,fieldSerialize,fieldValue,resetForm,clearForm,clearFields的 应用
    jQuery Form 表单提交插件-----ajaxSubmit() 的应用
    jQuery Form 表单提交插件-----ajaxForm() 的应用
    jQuery Form 表单提交插件----Form 简介,官方文档,官方下载地址
    jQuery Validate 表单验证插件----自定义一个验证方法
    jQuery Validate 表单验证插件----自定义校验结果样式
  • 原文地址:https://www.cnblogs.com/Moon-Face/p/4496453.html
Copyright © 2011-2022 走看看