標籤:
原始碼是這樣的:
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代碼是針對位元組數組簽名返回位元組數組, 所以這裡對傳回值需要處理一下, 處理成位元組數組
<?phprequire_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對字串編碼的結果和預期不符):
<?phpclass 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;}}
一段JAVA簽名演算法的PHP改寫