亚马逊c++SDK验证签名定制

Linux系统的附加要求(GNU编译器集合(GCC)4.9或更高版本

(官方教程https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/setup.html

http://sdk.amazonaws.com/cpp/api/LATEST/index.html

要编译在Linux上,您必须具备的头文件(-dev包)为libcurllibopenssl, libuuidzlib,和可选,libpulse亚马逊波利支持。通常,您可以在系统的包管理器中找到包。

在基于Debian / Ubuntu的系统上安装这些软件包

sudo apt-get install libcurl4-openssl-dev libssl-dev uuid-dev zlib1g-dev libpulse-dev

在基于Redhat / Fedora/Centos的系统上安装这些软件包

sudo yum install libcurl-devel openssl-devel libuuid-devel pulseaudio-devel

 

1.源码包下载地址

https://github.com/aws/aws-sdk-cpp/archive/master.zip 

2.cmake不得低于3.0(可以到官网下载安装)

推荐安装教程https://blog.csdn.net/fxnawm/article/details/78489586

3.创建一个用于创建构建文件的目录,并在其中生成必要的构建文件。

mkdir sdk_build

cd sdk_build

cmake <path/to/sdk/source>

4.生成makefile文件

cmake -DCMAKE_BUILD_TYPE=Release /usr/local/aws-sdk-cpp-master -DOPENSSL_ROOT_DIR=/usr/local/openssl

//-DCMAKE_BUILD_TYPE    指定编译的版本

//随后指定makefile生成的目录

//-DOPENSSL_ROOT_DIR指定openssl的主目录(国内一些产品更改了s3的签名算法,修改了他的签名用到了openssl)

5.修改cmake生成的配置文件要去掉 -Werror 参数(将警告视为错误)

进入cmake生成makefile的目录:

去掉核心模块vi aws-cpp-sdk-core/CMakeFiles/aws-cpp-sdk-core.dir/flags.make 去掉-Werror

修改s3模块配置vi aws-cpp-sdk-s3/CMakeFiles/aws-cpp-sdk-s3.dir/flags.make 去掉-Werror

其它模块与之类似

6.编译自己所需要的模块(不建议全部编译,亚马逊这整个工程太大了,包含的东西很多可能用不到,而且这样很耗时,但aws-cpp-sdk-core核心模块必须先编译了再去编译你所需要的模块)

编译命令:

编译aws-cpp-sdk-core

make -j `nproc` -C aws-cpp-sdk-core

make install DESTDIR=/usr/local/inphase/aws  -C aws-cpp-sdk-core

编译aws-cpp-sdk-s3

make -j `nproc` -C aws-cpp-sdk-s3

make install DESTDIR=/devinphase/inphase/aws  -C aws-cpp-sdk-s3

其它与之类似

(make参数可参考http://man.linuxde.net/make`nproc`参数是取当前cpu的核数

亚马逊c++验证算法修改

 

auth目录:签名验证相关;

client目录:亚马逊客户端请求实例,所有的s3内的所有请求都需要实例化这个client

config目录:加载配置文件,签名时可以将一些配置写入一个文件通过这个配置文件加载器来加载;这个官方推荐的做法;

external目录:亚马逊封装的JsonCpp 和tinyxml第三方库,很多地方使用到这2个库

http目录:封装了cul和Windows平台的winhttp用于http跨平台

internal目录:http资源获取的类

platform目录:平台相关

utils目录:一些些见名知意的工具类

 

AWSAuthSigner抽象类定义签名验证必须实现的接口

AWSAuthV4Signer类继承自AWSAuthSigner实现AWSAuthSigner所有接口,这个是亚马逊通用的v4签名验证方式

AWSNullSigner类继承自AWSAuthSigner但它什么都没做,就是明文不签名验证

TelecomOOSSigner类继承自AWSAuthSigner实现AWSAuthSigner所有接口,这个是自己定制的修改了签名的方式,以适用于国内某平台的签名标准,使用了openssl库

代码如下:

bool TelecomOOSSigner::SignRequest(Aws::Http::HttpRequest& request, bool signBody) const
{
	AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials();

	//don't sign anonymous requests
	if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty())
	{
		return true;
	}

	if (!credentials.GetSessionToken().empty())
	{
		request.SetAwsSessionToken(credentials.GetSessionToken());
	}

	Aws::String payloadHash;
	switch (m_payloadSigningPolicy)
	{
	case PayloadSigningPolicy::Always:
		signBody = true;
		break;
	case PayloadSigningPolicy::Never:
		signBody = false;
		break;
	case PayloadSigningPolicy::RequestDependent:
		// respect the request setting
	default:
		break;
	}

	if (signBody /*|| "binary/octet-stream" != request.GetContentType().c_str()*/ )
	{
		payloadHash.assign(ComputePayloadHash(request));
		if (payloadHash.empty())
		{
			return false;
		}
	}
	else
	{
		AWS_LOGSTREAM_DEBUG(v4LogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody
			<< " http scheme=" << Http::SchemeMapper::ToString(request.GetUri().GetScheme()));
	}
	//calculate date header to use in internal signature (this also goes into date header).
	DateTime now = GetSigningTimestamp();
	Aws::String dateHeaderValue = now.ToGmtString(OOSLONG_DATE_FORMAT_STR);
	request.SetDate(dateHeaderValue);

	Aws::StringStream signedHeadersStream;
	signedHeadersStream << HttpMethodMapper::GetNameForHttpMethod(request.GetMethod());
	signedHeadersStream << NEWLINE;
	//resourcePath
	Aws::String strBucket = request.GetHeaders().at("host");
	auto pos = strBucket.find(".");
	strBucket.erase(strBucket.begin() + pos, strBucket.end());//bucket

	Aws::String strurls = request.GetUri().GetPath();//urlpath
	strurls.erase(0, 1);

	Aws::String resourcePath =
		"/" +
		((!strBucket.empty()) ? strBucket : "") +
		((! strurls.empty()) ? strurls : "/");
	
	const Aws::String  startsWith = "x-amz-";
	HeaderValueCollection reqHeader = request.GetHeaders();
	HeaderValueCollection interestingHeaders;

	if ( ! reqHeader.empty() && reqHeader.size() >0 )
	{
		for  (auto iter : reqHeader)
		{
			Aws::String key = iter.first;
			Aws::String value = iter.second;
			if (key.empty()) continue;

			key = Aws::Utils::StringUtils::ToLower(key.c_str());
			// Ignore any headers that are not particularly interesting.
			if (key == "content-type" || key == "content-md5" || key == "date" || (key.compare(0, startsWith.length(), startsWith) == 0)
		)
			{
				interestingHeaders.insert(std::make_pair(key, value));
			}

		}
	}
	
	// Remove default date timestamp if "x-amz-date" is set.
	auto iter = interestingHeaders.find("x-amz-date");
	if (iter != interestingHeaders.end()) {
		iter->second = "";
	}
	
	// These headers require that we still put a new line in after them,
	// even if they don't exist.
	if ( interestingHeaders.find("content-type") == interestingHeaders.end()) {
		interestingHeaders.insert(std::make_pair("content-type", ""));
	}
	
	if (interestingHeaders.find("content-md5") == interestingHeaders.end()) {
		interestingHeaders.insert(std::make_pair("content-md5", ""));
	}

	for (auto parameter : reqHeader)
	{
		
		if (parameter.first.compare(0, startsWith.length(), startsWith) == 0)
		{
			interestingHeaders.insert(std::make_pair(parameter.first, parameter.second));
		}
	}
	
	// Add all the interesting headers (i.e.: all that startwith x-amz- ;-))
	for  (auto  paramerEntry : interestingHeaders)
	{
		Aws::String key =paramerEntry.first;
		Aws::String value = paramerEntry.second;

		if (paramerEntry.first.compare(0, startsWith.length(), startsWith) == 0)
		{
			signedHeadersStream << paramerEntry.first.c_str() << ":" << paramerEntry.second.c_str() << NEWLINE;
		}
		else
		{
			signedHeadersStream << paramerEntry.second.c_str() << NEWLINE;
		}
	}
			
		//Add all the interesting parameters
		signedHeadersStream << resourcePath;
		QueryStringParameterCollection paramers = request.GetQueryStringParameters();
		std::vector<Aws::String> parameterNames;
		for  (auto paramer : paramers)
		{
			parameterNames.push_back(paramer.first) ;
		}

		std::sort(parameterNames.begin(), parameterNames.end(),std::less<Aws::String>());
		Aws::String strSeparator("?");
		std::set<Aws::String>::iterator iters;
		for(auto parameterName : parameterNames)
		{
			iters = m_canonicalizedResource.find(parameterName);
			if (iters == m_canonicalizedResource.end()) {
				continue;
			}
			signedHeadersStream << strSeparator;
			signedHeadersStream << parameterName;

			Aws::String parameterValue = paramers.find(parameterName)->second;
			if (! parameterValue.empty())
			{
				signedHeadersStream << parameterValue;
			}
			strSeparator = "&";
		}

	//calculate signed headers parameter
	Aws::String signedHeadersValue = signedHeadersStream.str();
	AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed  value:" << signedHeadersValue);

	//now compute HMAC-SHA1 on that request string
	//CHMAC_SHA1 hmac;
	typedef unsigned char BYTE;
	//unsigned char  sigval[256];
	unsigned char * sigval = nullptr;
 	unsigned int iHmacLength = 0;

	HmacEncode((const char *)credentials.GetAWSSecretKey().c_str(), credentials.GetAWSSecretKey().length(), (const char *)signedHeadersValue.c_str(), signedHeadersValue.length(),sigval, iHmacLength);

	ByteBuffer message(sigval, iHmacLength);
	Aws::String cannonicalRequestHash = HashingUtils::Base64Encode(message);
// 	cannonicalRequestHash = URI::URLEncodePath(cannonicalRequestHash);
	if (sigval) {
		free(sigval);
		cout << "hmac is freed!" << endl;
	}
	Aws::StringStream ss;
	ss << cannonicalRequestHash;
	auto awsAuthString = ss.str();
	std::cout << "hmac :" << awsAuthString << std::endl;
	AWS_LOGSTREAM_DEBUG(v4LogTag, "Signing request with: " << awsAuthString);
	request.SetAwsAuthorization("AWS " + credentials.GetAWSAccessKeyId() + ":" + awsAuthString);

	return true;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值