diff options
Diffstat (limited to 'cpp/src/Ice/Base64.cpp')
-rw-r--r-- | cpp/src/Ice/Base64.cpp | 343 |
1 files changed, 124 insertions, 219 deletions
diff --git a/cpp/src/Ice/Base64.cpp b/cpp/src/Ice/Base64.cpp index 566785cc48b..445ab98c90c 100644 --- a/cpp/src/Ice/Base64.cpp +++ b/cpp/src/Ice/Base64.cpp @@ -8,262 +8,167 @@ // ********************************************************************** #include <Ice/Base64.h> +#include <Ice/LocalException.h> +#include <IceUtil/StringConverter.h> +#include <IceUtil/StringUtil.h> +#include <IceUtil/UniqueRef.h> #include <iterator> +#if defined(ICE_OS_UWP) +using namespace Platform; +using namespace Windows::Security::Cryptography; +using namespace Windows::Storage::Streams; +#elif defined(_WIN32) +# include <Wincrypt.h> +#elif defined(__APPLE__) +# include <Security/Security.h> +#else +# include <openssl/bio.h> +# include <openssl/evp.h> +#endif + +using namespace IceUtil; using namespace std; string -IceInternal::Base64::encode(const vector<unsigned char>& plainSeq) +IceInternal::Base64::encode(const vector<unsigned char>& decoded) { - string retval; - - if(plainSeq.size() == 0) - { - return retval; - } - - // Reserve enough space for the returned base64 string - size_t base64Bytes = (((plainSeq.size() * 4) / 3) + 1); - size_t newlineBytes = (((base64Bytes * 2) / 76) + 1); - size_t totalBytes = base64Bytes + newlineBytes; - - retval.reserve(totalBytes); - - unsigned char by1 = 0; - unsigned char by2 = 0; - unsigned char by3 = 0; - unsigned char by4 = 0; - unsigned char by5 = 0; - unsigned char by6 = 0; - unsigned char by7 = 0; - - for(size_t i = 0; i < plainSeq.size(); i += 3) +#if defined(ICE_OS_UWP) + try { - by1 = plainSeq[i]; - by2 = 0; - by3 = 0; - - if((i + 1) < plainSeq.size()) - { - by2 = plainSeq[i+1]; - } - - if((i + 2) < plainSeq.size()) - { - by3 = plainSeq[i+2]; - } - - by4 = by1 >> 2; - by5 = ((by1 & 0x3) << 4) | (by2 >> 4); - by6 = ((by2 & 0xf) << 2) | (by3 >> 6); - by7 = by3 & 0x3f; - - retval += encode(by4); - retval += encode(by5); - - if((i + 1) < plainSeq.size()) - { - retval += encode(by6); - } - else - { - retval += "="; - } - - if((i + 2) < plainSeq.size()) - { - retval += encode(by7); - } - else - { - retval += "="; - } + ArrayReference<unsigned char> data(const_cast<unsigned char*>(&decoded[0]), + static_cast<unsigned int>(decoded.size())); + auto writer = ref new DataWriter(); + writer->WriteBytes(data); + return wstringToString(CryptographicBuffer::EncodeToBase64String(writer->DetachBuffer())->Data()); } - - string outString; - outString.reserve(totalBytes); - string::iterator iter = retval.begin(); - - while((retval.end() - iter) > 76) - { - copy(iter, iter+76, back_inserter(outString)); - outString += "\r\n"; - iter += 76; - } - - copy(iter, retval.end(), back_inserter(outString)); - - return outString; -} - -vector<unsigned char> -IceInternal::Base64::decode(const string& str) -{ - string newStr; - - newStr.reserve(str.length()); - - for(size_t j = 0; j < str.length(); j++) - { - if(isBase64(str[j])) - { - newStr += str[j]; - } - } - - vector<unsigned char> retval; - - if(newStr.length() == 0) - { - return retval; - } - - // Note: This is how we were previously computing the size of the return - // sequence. The method below is more efficient (and correct). - // size_t lines = str.size() / 78; - // size_t totalBytes = (lines * 76) + (((str.size() - (lines * 78)) * 3) / 4); - - // Figure out how long the final sequence is going to be. - size_t totalBytes = (newStr.size() * 3 / 4) + 1; - - retval.reserve(totalBytes); - - unsigned char by1 = 0; - unsigned char by2 = 0; - unsigned char by3 = 0; - unsigned char by4 = 0; - - char c1, c2, c3, c4; - - for(size_t i = 0; i < newStr.length(); i += 4) + catch(Platform::Exception^ ex) { - c1 = 'A'; - c2 = 'A'; - c3 = 'A'; - c4 = 'A'; - - c1 = newStr[i]; - - if((i + 1) < newStr.length()) - { - c2 = newStr[i + 1]; - } - - if((i + 2) < newStr.length()) - { - c3 = newStr[i + 2]; - } - - if((i + 3) < newStr.length()) - { - c4 = newStr[i + 3]; - } - - by1 = decode(c1); - by2 = decode(c2); - by3 = decode(c3); - by4 = decode(c4); - - retval.push_back((by1 << 2) | (by2 >> 4)); - - if(c3 != '=') - { - retval.push_back(((by2 & 0xf) << 4) | (by3 >> 2)); - } - - if(c4 != '=') - { - retval.push_back(((by3 & 0x3) << 6) | by4); - } + throw IllegalArgumentException(__FILE__, __LINE__, wstringToString(ex->Message->Data())); } - - return retval; -} - -bool -IceInternal::Base64::isBase64(char c) -{ - if(c >= 'A' && c <= 'Z') +#elif defined(_WIN32) + DWORD sz = 0; + const DWORD flags = CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF; + if(!CryptBinaryToString(&decoded[0], static_cast<DWORD>(decoded.size()), flags, 0, &sz)) { - return true; + throw IllegalArgumentException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString()); } - - if(c >= 'a' && c <= 'z') + std::string encoded; + encoded.resize(sz - 1); + if(!CryptBinaryToString(&decoded[0], static_cast<DWORD>(decoded.size()), flags, &encoded[0], &sz)) { - return true; + throw IllegalArgumentException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString()); } - - if(c >= '0' && c <= '9') + return encoded; +#elif defined(__APPLE__) + CFErrorRef err = 0; + UniqueRef<SecTransformRef> encoder(SecEncodeTransformCreate(kSecBase64Encoding, &err)); + if(err) { - return true; + CFRelease(err); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - if(c == '+') + CFDataRef in = CFDataCreateWithBytesNoCopy(0, &decoded[0], decoded.size(), kCFAllocatorNull); + SecTransformSetAttribute(encoder.get(), kSecTransformInputAttributeName, in, &err); + if(err) { - return true; + CFRelease(err); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - if(c == '/') + UniqueRef<CFDataRef> data(static_cast<CFDataRef>(SecTransformExecute(encoder.get(), &err))); + if(err) { - return true; + CFRelease(err); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - if(c == '=') + return string(reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())), CFDataGetLength(data.get())); +#else + BIO* b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO* bio = BIO_new(BIO_s_mem()); + BIO_push(b64, bio); + if(BIO_write(b64, &buffer[0], buffer.size()) <= 0) { - return true; + BIO_free_all(b64); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } + BIO_flush(b64); - return false; + char* data; + long size = BIO_get_mem_data(bio, &data); + string encoded(data, size); + BIO_free_all(b64); + return encoded; +#endif } -char -IceInternal::Base64::encode(unsigned char uc) +vector<unsigned char> +IceInternal::Base64::decode(const string& encoded) { - if(uc < 26) - { - return 'A' + uc; - } - - if(uc < 52) - { - return 'a' + (uc - 26); + vector<unsigned char> decoded; +#if defined(ICE_OS_UWP) + try + { + auto reader = DataReader::FromBuffer( + CryptographicBuffer::DecodeFromBase64String(ref new String(stringToWstring(encoded).c_str()))); + decoded.resize(reader->UnconsumedBufferLength); + if(!decoded.empty()) + { + reader->ReadBytes(ArrayReference<unsigned char>(&decoded[0], reader->UnconsumedBufferLength)); + } } - - if(uc < 62) + catch(Platform::Exception^ ex) { - return '0' + (uc - 52); + throw IllegalArgumentException(__FILE__, __LINE__, wstringToString(ex->Message->Data())); } - - if(uc == 62) +#elif defined(_WIN32) + DWORD sz = static_cast<DWORD>(encoded.size()); + decoded.resize(sz); + if(!CryptStringToBinary(encoded.c_str(), sz, CRYPT_STRING_BASE64, &decoded[0], &sz, 0, 0)) { - return '+'; + throw IllegalArgumentException(__FILE__, __LINE__, IceUtilInternal::lastErrorToString()); } - - return '/'; -} - -unsigned char -IceInternal::Base64::decode(char c) -{ - if(c >= 'A' && c <= 'Z') + decoded.resize(sz); +#elif defined(__APPLE__) + CFErrorRef err = 0; + UniqueRef<SecTransformRef> decoder(SecDecodeTransformCreate(kSecBase64Encoding, &err)); + if(err) { - return c - 'A'; + CFRelease(err); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - if(c >= 'a' && c <= 'z') + CFDataRef input = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const unsigned char*>(&encoded[0]), + encoded.size(), kCFAllocatorNull); + SecTransformSetAttribute(decoder.get(), kSecTransformInputAttributeName, input, &err); + if(err) { - return c - 'a' + 26; + CFRelease(err); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - if(c >= '0' && c <= '9') + UniqueRef<CFDataRef> data(static_cast<CFDataRef>(SecTransformExecute(decoder.get(), &err))); + if(err) { - return c - '0' + 52; + CFRelease(err); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - if(c == '+') + vector<unsigned char> out; + decoded.resize(CFDataGetLength(data.get())); + memcpy(&decoded[0], CFDataGetBytePtr(data.get()), decoded.size()); + return out; +#else + BIO* b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + BIO* bio = BIO_new_mem_buf(&encoded[0], static_cast<int>(encoded.size())); + BIO_push(b64, bio); + decoded.resize(encoded.size()); + int sz = BIO_read(b64, &decoded[0], static_cast<int>(decoded.size())); + if(sz <= 0) { - return 62; + BIO_free_all(b64); + throw IllegalArgumentException(__FILE__, __LINE__, "Base64 bad data"); } - - return 63; + decoded.resize(sz); + BIO_free_all(b64); +#endif + return decoded; } |