一段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;

	}

}

  

你可能感兴趣的:(java)