Home | History | Annotate | Download | only in hidl
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      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 "Base64.h"
     18 
     19 #include <string>
     20 
     21 namespace android {
     22 namespace hardware {
     23 namespace drm {
     24 namespace V1_2 {
     25 namespace clearkey {
     26 
     27 sp<Buffer> decodeBase64(const std::string &s) {
     28     size_t n = s.size();
     29 
     30     if ((n % 4) != 0) {
     31         return nullptr;
     32     }
     33 
     34     size_t padding = 0;
     35     if (n >= 1 && s.c_str()[n - 1] == '=') {
     36         padding = 1;
     37 
     38         if (n >= 2 && s.c_str()[n - 2] == '=') {
     39             padding = 2;
     40 
     41             if (n >= 3 && s.c_str()[n - 3] == '=') {
     42                 padding = 3;
     43             }
     44         }
     45     }
     46 
     47     // We divide first to avoid overflow. It's OK to do this because we
     48     // already made sure that n % 4 == 0.
     49     size_t outLen = (n / 4) * 3 - padding;
     50 
     51     sp<Buffer> buffer = new Buffer(outLen);
     52     uint8_t *out = buffer->data();
     53     if (out == nullptr || buffer->size() < outLen) {
     54         return nullptr;
     55     }
     56 
     57     size_t j = 0;
     58     uint32_t accum = 0;
     59     for (size_t i = 0; i < n; ++i) {
     60         char c = s.c_str()[i];
     61         unsigned value;
     62         if (c >= 'A' && c <= 'Z') {
     63             value = c - 'A';
     64         } else if (c >= 'a' && c <= 'z') {
     65             value = 26 + c - 'a';
     66         } else if (c >= '0' && c <= '9') {
     67             value = 52 + c - '0';
     68         } else if (c == '+' || c == '-') {
     69             value = 62;
     70         } else if (c == '/' || c == '_') {
     71             value = 63;
     72         } else if (c != '=') {
     73             return nullptr;
     74         } else {
     75             if (i < n - padding) {
     76                 return nullptr;
     77             }
     78 
     79             value = 0;
     80         }
     81 
     82         accum = (accum << 6) | value;
     83 
     84         if (((i + 1) % 4) == 0) {
     85             if (j < outLen) { out[j++] = (accum >> 16); }
     86             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
     87             if (j < outLen) { out[j++] = accum & 0xff; }
     88 
     89             accum = 0;
     90         }
     91     }
     92 
     93     return buffer;
     94 }
     95 
     96 static char encode6Bit(unsigned x) {
     97     if (x <= 25) {
     98         return 'A' + x;
     99     } else if (x <= 51) {
    100         return 'a' + x - 26;
    101     } else if (x <= 61) {
    102         return '0' + x - 52;
    103     } else if (x == 62) {
    104         return '+';
    105     } else {
    106         return '/';
    107     }
    108 }
    109 
    110 void encodeBase64(const void *_data, size_t size, std::string *out) {
    111     out->clear();
    112 
    113     const uint8_t *data = (const uint8_t *)_data;
    114 
    115     size_t i;
    116     for (i = 0; i < (size / 3) * 3; i += 3) {
    117         uint8_t x1 = data[i];
    118         uint8_t x2 = data[i + 1];
    119         uint8_t x3 = data[i + 2];
    120 
    121         out->push_back(encode6Bit(x1 >> 2));
    122         out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
    123         out->push_back(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
    124         out->push_back(encode6Bit(x3 & 0x3f));
    125     }
    126     switch (size % 3) {
    127         case 0:
    128             break;
    129         case 2:
    130         {
    131             uint8_t x1 = data[i];
    132             uint8_t x2 = data[i + 1];
    133             out->push_back(encode6Bit(x1 >> 2));
    134             out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
    135             out->push_back(encode6Bit((x2 << 2) & 0x3f));
    136             out->push_back('=');
    137             break;
    138         }
    139         default:
    140         {
    141             uint8_t x1 = data[i];
    142             out->push_back(encode6Bit(x1 >> 2));
    143             out->push_back(encode6Bit((x1 << 4) & 0x3f));
    144             out->append("==");
    145             break;
    146         }
    147     }
    148 }
    149 
    150 void encodeBase64Url(const void *_data, size_t size, std::string *out) {
    151     encodeBase64(_data, size, out);
    152 
    153     if ((std::string::npos != out->find("+")) ||
    154             (std::string::npos != out->find("/"))) {
    155         size_t outLen = out->size();
    156         char *base64url = new char[outLen];
    157         for (size_t i = 0; i < outLen; ++i) {
    158             if (out->c_str()[i] == '+')
    159                 base64url[i] = '-';
    160             else if (out->c_str()[i] == '/')
    161                 base64url[i] = '_';
    162             else
    163                 base64url[i] = out->c_str()[i];
    164         }
    165 
    166         out->assign(base64url, outLen);
    167         delete[] base64url;
    168     }
    169 }
    170 
    171 } // namespace clearkey
    172 } // namespace V1_2
    173 } // namespace drm
    174 } // namespace hardware
    175 } // namespace android
    176