LCOV - differential code coverage report
Current view: top level - contrib/pgcrypto - pgp-armor.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 89.2 % 231 206 25 206
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 10 10 10
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 89.2 % 231 206 25 206
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 10 10 10

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*
                                  2                 :  * pgp-armor.c
                                  3                 :  *      PGP ascii-armor.
                                  4                 :  *
                                  5                 :  * Copyright (c) 2005 Marko Kreen
                                  6                 :  * All rights reserved.
                                  7                 :  *
                                  8                 :  * Redistribution and use in source and binary forms, with or without
                                  9                 :  * modification, are permitted provided that the following conditions
                                 10                 :  * are met:
                                 11                 :  * 1. Redistributions of source code must retain the above copyright
                                 12                 :  *    notice, this list of conditions and the following disclaimer.
                                 13                 :  * 2. Redistributions in binary form must reproduce the above copyright
                                 14                 :  *    notice, this list of conditions and the following disclaimer in the
                                 15                 :  *    documentation and/or other materials provided with the distribution.
                                 16                 :  *
                                 17                 :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                                 18                 :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                                 19                 :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                                 20                 :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                                 21                 :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                                 22                 :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                                 23                 :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                                 24                 :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                                 25                 :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                                 26                 :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                                 27                 :  * SUCH DAMAGE.
                                 28                 :  *
                                 29                 :  * contrib/pgcrypto/pgp-armor.c
                                 30                 :  */
                                 31                 : 
                                 32                 : #include "postgres.h"
                                 33                 : 
                                 34                 : #include "pgp.h"
                                 35                 : #include "px.h"
                                 36                 : 
                                 37                 : /*
                                 38                 :  * BASE64 - duplicated :(
                                 39                 :  */
                                 40                 : 
                                 41                 : static const unsigned char _base64[] =
                                 42                 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                                 43                 : 
                                 44                 : static int
 1866 tgl                        45 CBC          10 : pg_base64_encode(const uint8 *src, unsigned len, uint8 *dst)
                                 46                 : {
                                 47                 :     uint8      *p,
 6482 bruce                      48              10 :                *lend = dst + 76;
                                 49                 :     const uint8 *s,
                                 50              10 :                *end = src + len;
                                 51              10 :     int         pos = 2;
                                 52              10 :     unsigned long buf = 0;
                                 53                 : 
                                 54              10 :     s = src;
                                 55              10 :     p = dst;
                                 56                 : 
                                 57             131 :     while (s < end)
                                 58                 :     {
                                 59             121 :         buf |= *s << (pos << 3);
                                 60             121 :         pos--;
                                 61             121 :         s++;
                                 62                 : 
                                 63                 :         /*
                                 64                 :          * write it out
                                 65                 :          */
                                 66             121 :         if (pos < 0)
                                 67                 :         {
                                 68              37 :             *p++ = _base64[(buf >> 18) & 0x3f];
                                 69              37 :             *p++ = _base64[(buf >> 12) & 0x3f];
                                 70              37 :             *p++ = _base64[(buf >> 6) & 0x3f];
                                 71              37 :             *p++ = _base64[buf & 0x3f];
                                 72                 : 
                                 73              37 :             pos = 2;
                                 74              37 :             buf = 0;
                                 75                 :         }
                                 76             121 :         if (p >= lend)
                                 77                 :         {
                                 78               1 :             *p++ = '\n';
                                 79               1 :             lend = p + 76;
                                 80                 :         }
                                 81                 :     }
                                 82              10 :     if (pos != 2)
                                 83                 :     {
                                 84               6 :         *p++ = _base64[(buf >> 18) & 0x3f];
                                 85               6 :         *p++ = _base64[(buf >> 12) & 0x3f];
                                 86               6 :         *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
                                 87               6 :         *p++ = '=';
                                 88                 :     }
                                 89                 : 
                                 90              10 :     return p - dst;
                                 91                 : }
                                 92                 : 
                                 93                 : /* probably should use lookup table */
                                 94                 : static int
 1866 tgl                        95             178 : pg_base64_decode(const uint8 *src, unsigned len, uint8 *dst)
                                 96                 : {
 6482 bruce                      97             178 :     const uint8 *srcend = src + len,
 6385                            98             178 :                *s = src;
 6482                            99             178 :     uint8      *p = dst;
                                100                 :     char        c;
                                101             178 :     unsigned    b = 0;
                                102             178 :     unsigned long buf = 0;
                                103             178 :     int         pos = 0,
 6385                           104             178 :                 end = 0;
                                105                 : 
 6482                           106           85130 :     while (s < srcend)
                                107                 :     {
                                108           84952 :         c = *s++;
                                109           84952 :         if (c >= 'A' && c <= 'Z')
                                110           35636 :             b = c - 'A';
                                111           49316 :         else if (c >= 'a' && c <= 'z')
                                112           32762 :             b = c - 'a' + 26;
                                113           16554 :         else if (c >= '0' && c <= '9')
                                114           12460 :             b = c - '0' + 52;
                                115            4094 :         else if (c == '+')
                                116            1302 :             b = 62;
                                117            2792 :         else if (c == '/')
                                118            1344 :             b = 63;
                                119            1448 :         else if (c == '=')
                                120                 :         {
                                121                 :             /*
                                122                 :              * end sequence
                                123                 :              */
                                124             116 :             if (!end)
                                125                 :             {
                                126              67 :                 if (pos == 2)
                                127              49 :                     end = 1;
                                128              18 :                 else if (pos == 3)
                                129              18 :                     end = 2;
                                130                 :                 else
 6482 bruce                     131 UBC           0 :                     return PXE_PGP_CORRUPT_ARMOR;
                                132                 :             }
 6482 bruce                     133 CBC         116 :             b = 0;
                                134                 :         }
                                135            1332 :         else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
                                136            1332 :             continue;
                                137                 :         else
 6482 bruce                     138 UBC           0 :             return PXE_PGP_CORRUPT_ARMOR;
                                139                 : 
                                140                 :         /*
                                141                 :          * add it to buffer
                                142                 :          */
 6482 bruce                     143 CBC       83620 :         buf = (buf << 6) + b;
                                144           83620 :         pos++;
                                145           83620 :         if (pos == 4)
                                146                 :         {
                                147           20905 :             *p++ = (buf >> 16) & 255;
                                148           20905 :             if (end == 0 || end > 1)
                                149           20856 :                 *p++ = (buf >> 8) & 255;
                                150           20905 :             if (end == 0 || end > 2)
                                151           20838 :                 *p++ = buf & 255;
                                152           20905 :             buf = 0;
                                153           20905 :             pos = 0;
                                154                 :         }
                                155                 :     }
                                156                 : 
                                157             178 :     if (pos != 0)
 6482 bruce                     158 UBC           0 :         return PXE_PGP_CORRUPT_ARMOR;
 6482 bruce                     159 CBC         178 :     return p - dst;
                                160                 : }
                                161                 : 
                                162                 : static unsigned
 1866 tgl                       163              10 : pg_base64_enc_len(unsigned srclen)
                                164                 : {
                                165                 :     /*
                                166                 :      * 3 bytes will be converted to 4, linefeed after 76 chars
                                167                 :      */
 6482 bruce                     168              10 :     return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
                                169                 : }
                                170                 : 
                                171                 : static unsigned
 1866 tgl                       172              89 : pg_base64_dec_len(unsigned srclen)
                                173                 : {
 6482 bruce                     174              89 :     return (srclen * 3) >> 2;
                                175                 : }
                                176                 : 
                                177                 : /*
                                178                 :  * PGP armor
                                179                 :  */
                                180                 : 
                                181                 : static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n";
                                182                 : static const char *armor_footer = "\n-----END PGP MESSAGE-----\n";
                                183                 : 
                                184                 : /* CRC24 implementation from rfc2440 */
                                185                 : #define CRC24_INIT 0x00b704ceL
                                186                 : #define CRC24_POLY 0x01864cfbL
                                187                 : static long
                                188              99 : crc24(const uint8 *data, unsigned len)
                                189                 : {
                                190              99 :     unsigned    crc = CRC24_INIT;
                                191                 :     int         i;
                                192                 : 
                                193           62552 :     while (len--)
                                194                 :     {
                                195           62453 :         crc ^= (*data++) << 16;
                                196          562077 :         for (i = 0; i < 8; i++)
                                197                 :         {
                                198          499624 :             crc <<= 1;
                                199          499624 :             if (crc & 0x1000000)
                                200          250230 :                 crc ^= CRC24_POLY;
                                201                 :         }
                                202                 :     }
                                203              99 :     return crc & 0xffffffL;
                                204                 : }
                                205                 : 
                                206                 : void
 3112 heikki.linnakangas        207              10 : pgp_armor_encode(const uint8 *src, unsigned len, StringInfo dst,
                                208                 :                  int num_headers, char **keys, char **values)
                                209                 : {
                                210                 :     int         n;
                                211                 :     int         res;
                                212                 :     unsigned    b64len;
 6482 bruce                     213              10 :     unsigned    crc = crc24(src, len);
                                214                 : 
 3118 heikki.linnakangas        215              10 :     appendStringInfoString(dst, armor_header);
                                216                 : 
 3112                           217              17 :     for (n = 0; n < num_headers; n++)
                                218               7 :         appendStringInfo(dst, "%s: %s\n", keys[n], values[n]);
                                219              10 :     appendStringInfoChar(dst, '\n');
                                220                 : 
                                221                 :     /* make sure we have enough room to pg_base64_encode() */
 1866 tgl                       222              10 :     b64len = pg_base64_enc_len(len);
 3118 heikki.linnakangas        223              10 :     enlargeStringInfo(dst, (int) b64len);
                                224                 : 
 1866 tgl                       225              10 :     res = pg_base64_encode(src, len, (uint8 *) dst->data + dst->len);
 3118 heikki.linnakangas        226              10 :     if (res > b64len)
 3118 heikki.linnakangas        227 UBC           0 :         elog(FATAL, "overflow - encode estimate too small");
 3118 heikki.linnakangas        228 CBC          10 :     dst->len += res;
                                229                 : 
                                230              10 :     if (*(dst->data + dst->len - 1) != '\n')
                                231               6 :         appendStringInfoChar(dst, '\n');
                                232                 : 
                                233              10 :     appendStringInfoChar(dst, '=');
                                234              10 :     appendStringInfoChar(dst, _base64[(crc >> 18) & 0x3f]);
                                235              10 :     appendStringInfoChar(dst, _base64[(crc >> 12) & 0x3f]);
                                236              10 :     appendStringInfoChar(dst, _base64[(crc >> 6) & 0x3f]);
                                237              10 :     appendStringInfoChar(dst, _base64[crc & 0x3f]);
                                238                 : 
                                239              10 :     appendStringInfoString(dst, armor_footer);
 6482 bruce                     240              10 : }
                                241                 : 
                                242                 : static const uint8 *
                                243             207 : find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
                                244                 : {
                                245             207 :     const uint8 *p = data;
                                246                 : 
                                247             207 :     if (!strlen)
 6482 bruce                     248 UBC           0 :         return NULL;
 6482 bruce                     249 CBC         207 :     if (data_end - data < strlen)
 6482 bruce                     250 UBC           0 :         return NULL;
 6385 bruce                     251 CBC         222 :     while (p < data_end)
                                252                 :     {
 6482                           253             222 :         p = memchr(p, str[0], data_end - p);
                                254             222 :         if (p == NULL)
 6482 bruce                     255 UBC           0 :             return NULL;
 6482 bruce                     256 CBC         222 :         if (p + strlen > data_end)
 6482 bruce                     257 UBC           0 :             return NULL;
 6482 bruce                     258 CBC         222 :         if (memcmp(p, str, strlen) == 0)
                                259             207 :             return p;
                                260              15 :         p++;
                                261                 :     }
 6482 bruce                     262 UBC           0 :     return NULL;
                                263                 : }
                                264                 : 
                                265                 : static int
 6482 bruce                     266 CBC         206 : find_header(const uint8 *data, const uint8 *datend,
                                267                 :             const uint8 **start_p, int is_end)
                                268                 : {
                                269             206 :     const uint8 *p = data;
                                270                 :     static const char *start_sep = "-----BEGIN";
                                271                 :     static const char *end_sep = "-----END";
                                272             206 :     const char *sep = is_end ? end_sep : start_sep;
                                273                 : 
                                274                 :     /* find header line */
                                275                 :     while (1)
                                276                 :     {
                                277             207 :         p = find_str(p, datend, sep, strlen(sep));
                                278             207 :         if (p == NULL)
 6482 bruce                     279 UBC           0 :             return PXE_PGP_CORRUPT_ARMOR;
                                280                 :         /* it must start at beginning of line */
 6482 bruce                     281 CBC         207 :         if (p == data || *(p - 1) == '\n')
                                282                 :             break;
                                283               1 :         p += strlen(sep);
                                284                 :     }
                                285             206 :     *start_p = p;
                                286             206 :     p += strlen(sep);
                                287                 : 
                                288                 :     /* check if header text ok */
                                289            3412 :     for (; p < datend && *p != '-'; p++)
                                290                 :     {
                                291                 :         /* various junk can be there, but definitely not line-feed  */
                                292            3206 :         if (*p >= ' ')
                                293            3206 :             continue;
 6482 bruce                     294 UBC           0 :         return PXE_PGP_CORRUPT_ARMOR;
                                295                 :     }
 6482 bruce                     296 CBC         206 :     if (datend - p < 5 || memcmp(p, sep, 5) != 0)
 6482 bruce                     297 UBC           0 :         return PXE_PGP_CORRUPT_ARMOR;
 6482 bruce                     298 CBC         206 :     p += 5;
                                299                 : 
                                300                 :     /* check if at end of line */
                                301             206 :     if (p < datend)
                                302                 :     {
                                303             205 :         if (*p != '\n' && *p != '\r')
 6482 bruce                     304 UBC           0 :             return PXE_PGP_CORRUPT_ARMOR;
 6482 bruce                     305 CBC         205 :         if (*p == '\r')
                                306               2 :             p++;
                                307             205 :         if (p < datend && *p == '\n')
                                308             205 :             p++;
                                309                 :     }
                                310             206 :     return p - *start_p;
                                311                 : }
                                312                 : 
                                313                 : int
 3118 heikki.linnakangas        314              89 : pgp_armor_decode(const uint8 *src, int len, StringInfo dst)
                                315                 : {
 6482 bruce                     316              89 :     const uint8 *p = src;
                                317              89 :     const uint8 *data_end = src + len;
                                318                 :     long        crc;
                                319                 :     const uint8 *base64_start,
                                320                 :                *armor_end;
                                321              89 :     const uint8 *base64_end = NULL;
                                322                 :     uint8       buf[4];
                                323                 :     int         hlen;
                                324                 :     int         blen;
                                325              89 :     int         res = PXE_PGP_CORRUPT_ARMOR;
                                326                 : 
                                327                 :     /* armor start */
                                328              89 :     hlen = find_header(src, data_end, &p, 0);
                                329              89 :     if (hlen <= 0)
 6482 bruce                     330 UBC           0 :         goto out;
 6482 bruce                     331 CBC          89 :     p += hlen;
                                332                 : 
                                333                 :     /* armor end */
                                334              89 :     hlen = find_header(p, data_end, &armor_end, 1);
                                335              89 :     if (hlen <= 0)
 6482 bruce                     336 UBC           0 :         goto out;
                                337                 : 
                                338                 :     /* skip comments - find empty line */
 6482 bruce                     339 CBC         168 :     while (p < armor_end && *p != '\n' && *p != '\r')
                                340                 :     {
                                341              79 :         p = memchr(p, '\n', armor_end - p);
                                342              79 :         if (!p)
 6482 bruce                     343 UBC           0 :             goto out;
                                344                 : 
                                345                 :         /* step to start of next line */
 6482 bruce                     346 CBC          79 :         p++;
                                347                 :     }
                                348              89 :     base64_start = p;
                                349                 : 
                                350                 :     /* find crc pos */
                                351             624 :     for (p = armor_end; p >= base64_start; p--)
                                352             624 :         if (*p == '=')
                                353                 :         {
                                354              89 :             base64_end = p - 1;
                                355              89 :             break;
                                356                 :         }
                                357              89 :     if (base64_end == NULL)
 6482 bruce                     358 UBC           0 :         goto out;
                                359                 : 
                                360                 :     /* decode crc */
 1866 tgl                       361 CBC          89 :     if (pg_base64_decode(p + 1, 4, buf) != 3)
 6482 bruce                     362 UBC           0 :         goto out;
 6385 bruce                     363 CBC          89 :     crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
                                364                 : 
                                365                 :     /* decode data */
 1866 tgl                       366              89 :     blen = (int) pg_base64_dec_len(len);
 3118 heikki.linnakangas        367              89 :     enlargeStringInfo(dst, blen);
 1866 tgl                       368              89 :     res = pg_base64_decode(base64_start, base64_end - base64_start, (uint8 *) dst->data);
 3118 heikki.linnakangas        369              89 :     if (res > blen)
 3118 heikki.linnakangas        370 UBC           0 :         elog(FATAL, "overflow - decode estimate too small");
 3118 heikki.linnakangas        371 CBC          89 :     if (res >= 0)
                                372                 :     {
                                373              89 :         if (crc24((uint8 *) dst->data, res) == crc)
                                374              88 :             dst->len += res;
                                375                 :         else
                                376               1 :             res = PXE_PGP_CORRUPT_ARMOR;
                                377                 :     }
 6482 bruce                     378 UBC           0 : out:
 6482 bruce                     379 CBC          89 :     return res;
                                380                 : }
                                381                 : 
                                382                 : /*
                                383                 :  * Extracts all armor headers from an ASCII-armored input.
                                384                 :  *
                                385                 :  * Returns 0 on success, or PXE_* error code on error. On success, the
                                386                 :  * number of headers and their keys and values are returned in *nheaders,
                                387                 :  * *nkeys and *nvalues.
                                388                 :  */
                                389                 : int
 3112 heikki.linnakangas        390              14 : pgp_extract_armor_headers(const uint8 *src, unsigned len,
                                391                 :                           int *nheaders, char ***keys, char ***values)
                                392                 : {
                                393              14 :     const uint8 *data_end = src + len;
                                394                 :     const uint8 *p;
                                395                 :     const uint8 *base64_start;
                                396                 :     const uint8 *armor_start;
                                397                 :     const uint8 *armor_end;
                                398                 :     Size        armor_len;
                                399                 :     char       *line;
                                400                 :     char       *nextline;
                                401                 :     char       *eol,
                                402                 :                *colon;
                                403                 :     int         hlen;
                                404                 :     char       *buf;
                                405                 :     int         hdrlines;
                                406                 :     int         n;
                                407                 : 
                                408                 :     /* armor start */
                                409              14 :     hlen = find_header(src, data_end, &armor_start, 0);
                                410              14 :     if (hlen <= 0)
 3112 heikki.linnakangas        411 UBC           0 :         return PXE_PGP_CORRUPT_ARMOR;
 3112 heikki.linnakangas        412 CBC          14 :     armor_start += hlen;
                                413                 : 
                                414                 :     /* armor end */
                                415              14 :     hlen = find_header(armor_start, data_end, &armor_end, 1);
                                416              14 :     if (hlen <= 0)
 3112 heikki.linnakangas        417 UBC           0 :         return PXE_PGP_CORRUPT_ARMOR;
                                418                 : 
                                419                 :     /* Count the number of armor header lines. */
 3112 heikki.linnakangas        420 CBC          14 :     hdrlines = 0;
                                421              14 :     p = armor_start;
                                422              40 :     while (p < armor_end && *p != '\n' && *p != '\r')
                                423                 :     {
                                424              26 :         p = memchr(p, '\n', armor_end - p);
                                425              26 :         if (!p)
 3112 heikki.linnakangas        426 UBC           0 :             return PXE_PGP_CORRUPT_ARMOR;
                                427                 : 
                                428                 :         /* step to start of next line */
 3112 heikki.linnakangas        429 CBC          26 :         p++;
                                430              26 :         hdrlines++;
                                431                 :     }
                                432              14 :     base64_start = p;
                                433                 : 
                                434                 :     /*
                                435                 :      * Make a modifiable copy of the part of the input that contains the
                                436                 :      * headers. The returned key/value pointers will point inside the buffer.
                                437                 :      */
                                438              14 :     armor_len = base64_start - armor_start;
                                439              14 :     buf = palloc(armor_len + 1);
                                440              14 :     memcpy(buf, armor_start, armor_len);
                                441              14 :     buf[armor_len] = '\0';
                                442                 : 
                                443                 :     /* Allocate return arrays */
                                444              14 :     *keys = (char **) palloc(hdrlines * sizeof(char *));
                                445              14 :     *values = (char **) palloc(hdrlines * sizeof(char *));
                                446                 : 
                                447                 :     /*
                                448                 :      * Split the header lines at newlines and ": " separators, and collect
                                449                 :      * pointers to the keys and values in the return arrays.
                                450                 :      */
                                451              14 :     n = 0;
                                452              14 :     line = buf;
                                453                 :     for (;;)
                                454                 :     {
                                455                 :         /* find end of line */
                                456              60 :         eol = strchr(line, '\n');
                                457              37 :         if (!eol)
                                458              12 :             break;
                                459              25 :         nextline = eol + 1;
                                460                 :         /* if the line ends in CR + LF, strip the CR */
                                461              25 :         if (eol > line && *(eol - 1) == '\r')
                                462               2 :             eol--;
                                463              25 :         *eol = '\0';
                                464                 : 
                                465                 :         /* find colon+space separating the key and value */
                                466              25 :         colon = strstr(line, ": ");
                                467              25 :         if (!colon)
                                468               2 :             return PXE_PGP_CORRUPT_ARMOR;
                                469              23 :         *colon = '\0';
                                470                 : 
                                471                 :         /* shouldn't happen, we counted the number of lines beforehand */
                                472              23 :         if (n >= hdrlines)
 3112 heikki.linnakangas        473 UBC           0 :             elog(ERROR, "unexpected number of armor header lines");
                                474                 : 
 3112 heikki.linnakangas        475 CBC          23 :         (*keys)[n] = line;
                                476              23 :         (*values)[n] = colon + 2;
                                477              23 :         n++;
                                478                 : 
                                479                 :         /* step to start of next line */
                                480              23 :         line = nextline;
                                481                 :     }
                                482                 : 
                                483              12 :     if (n != hdrlines)
 3112 heikki.linnakangas        484 UBC           0 :         elog(ERROR, "unexpected number of armor header lines");
                                485                 : 
 3112 heikki.linnakangas        486 CBC          12 :     *nheaders = n;
                                487              12 :     return 0;
                                488                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a