一段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; } }
本篇文章首发自魔芋红茶的博客https://www.cnblogs.com/Moon-Face/
请尊重其他人的劳动成功,转载请注明。