1 /*
2  * Copyright 2009-2017 Alibaba Cloud All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CipherOpenssl.h"
18 #include <openssl/rand.h>
19 
20 using namespace AlibabaCloud::OSS;
21 
toAlgorithmName(CipherAlgorithm algo)22 inline static std::string toAlgorithmName(CipherAlgorithm algo)
23 {
24     static const char* name[] = { "AES", "RSA"};
25     return name[static_cast<int>(algo) - static_cast<int>(CipherAlgorithm::AES)];
26 }
27 
toModeName(CipherMode mode)28 inline static std::string toModeName(CipherMode mode)
29 {
30     static const char* name[] = { "NONE", "ECB", "CBC", "CTR"};
31     return name[static_cast<int>(mode) - static_cast<int>(CipherMode::NONE)];
32 }
33 
toPaddingName(CipherPadding pad)34 inline static std::string toPaddingName(CipherPadding pad)
35 {
36     static const char* name[] = { "NoPadding", "PKCS1Padding", "PKCS5Padding", "PKCS7Padding", "ZeroPadding"};
37     return name[static_cast<int>(pad) - static_cast<int>(CipherPadding::NoPadding)];
38 }
39 
SymmetricCipher(const std::string & impl,CipherAlgorithm algo,CipherMode mode,CipherPadding pad)40 SymmetricCipher::SymmetricCipher(const std::string& impl, CipherAlgorithm algo, CipherMode mode, CipherPadding pad):
41     impl_(impl),
42     algorithm_(algo),
43     mode_(mode),
44     padding_(pad),
45     blockSize_(16)
46 {
47     name_ = toAlgorithmName(algo);
48     name_.append("/");
49     name_.append(toModeName(mode));
50     name_.append("/");
51     name_.append(toPaddingName(pad));
52 }
53 
GenerateIV(size_t length)54 ByteBuffer SymmetricCipher::GenerateIV(size_t length)
55 {
56     //use openssl rand func
57     ByteBuffer out = ByteBuffer(length);
58     RAND_bytes((unsigned char *)out.data(), length);
59     return out;
60 }
61 
GenerateKey(size_t length)62 ByteBuffer SymmetricCipher::GenerateKey(size_t length)
63 {
64     //use openssl rand func
65     ByteBuffer out = ByteBuffer(length);
66     RAND_bytes((unsigned char *)out.data(), length);
67     return out;
68 }
69 
70 template<class T>
71 typename std::enable_if<std::is_unsigned<T>::value, T>::type
bswap(T i,T j=0u,std::size_t n=0u)72 bswap(T i, T j = 0u, std::size_t n = 0u)
73 {
74     return n == sizeof(T) ? j :
75         bswap<T>(i >> CHAR_BIT, (j << CHAR_BIT) | (i & (T)(unsigned char)(-1)), n + 1);
76 }
77 
IncCTRCounter(const ByteBuffer & counter,uint64_t numberOfBlocks)78 ByteBuffer SymmetricCipher::IncCTRCounter(const ByteBuffer& counter, uint64_t numberOfBlocks)
79 {
80     ByteBuffer ctrCounter(counter);
81     uint64_t *ctrPtr = (uint64_t*)(ctrCounter.data() + ctrCounter.size() - sizeof(uint64_t));
82 
83     uint64_t n = 1;
84     if (*(char *)&n) {
85         //little
86         *ctrPtr = bswap<uint64_t>(bswap<uint64_t>(*ctrPtr) + numberOfBlocks);
87     }
88     else {
89         //big
90         *ctrPtr += numberOfBlocks;
91     }
92 
93     return ctrCounter;
94 }
95 
CreateAES128_CTRImpl()96 std::shared_ptr<SymmetricCipher> SymmetricCipher::CreateAES128_CTRImpl()
97 {
98     return std::make_shared<SymmetricCipherOpenssl>(EVP_aes_128_ctr(),
99         CipherAlgorithm::AES, CipherMode::CTR, CipherPadding::NoPadding);
100 }
101 
CreateAES128_CBCImpl()102 std::shared_ptr<SymmetricCipher> SymmetricCipher::CreateAES128_CBCImpl()
103 {
104     return std::make_shared<SymmetricCipherOpenssl>(EVP_aes_128_cbc(),
105         CipherAlgorithm::AES, CipherMode::CBC, CipherPadding::PKCS5Padding);
106 }
107 
CreateAES256_CTRImpl()108 std::shared_ptr<SymmetricCipher> SymmetricCipher::CreateAES256_CTRImpl()
109 {
110     return std::make_shared<SymmetricCipherOpenssl>(EVP_aes_256_ctr(),
111         CipherAlgorithm::AES, CipherMode::CTR, CipherPadding::NoPadding);
112 }
113 
114 
115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
116 
AsymmetricCipher(const std::string & impl,CipherAlgorithm algo,CipherMode mode,CipherPadding pad)117 AsymmetricCipher::AsymmetricCipher(const std::string& impl, CipherAlgorithm algo, CipherMode mode, CipherPadding pad) :
118     impl_(impl),
119     algorithm_(algo),
120     mode_(mode),
121     padding_(pad)
122 {
123     name_ = toAlgorithmName(algo);
124     name_.append("/");
125     name_.append(toModeName(mode));
126     name_.append("/");
127     name_.append(toPaddingName(pad));
128 }
129 
CreateRSA_NONEImpl()130 std::shared_ptr<AsymmetricCipher> AsymmetricCipher::CreateRSA_NONEImpl()
131 {
132     return std::make_shared<AsymmetricCipherOpenssl>(CipherAlgorithm::RSA, CipherMode::NONE, CipherPadding::PKCS1Padding);
133 }
134 
135 
136 
137