]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - crypto.c
implemented r_transparent_alphatocoverage 2 which promotes alphablend if
[xonotic/darkplaces.git] / crypto.c
index fa2ea67cde6db099aed949d0545368dd359658f8..6a40df4c7233b4c259c9e1c14ed839cc3caa486e 100644 (file)
--- a/crypto.c
+++ b/crypto.c
@@ -143,6 +143,7 @@ static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, co
 #define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN
 #define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
 #define qd0_blind_id_sign_with_private_id_sign d0_blind_id_sign_with_private_id_sign
+#define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached
 
 #else
 
@@ -191,6 +192,7 @@ static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void)
 static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void);
 static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen);
+static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign_detached) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen);
 static dllfunction_t d0_blind_id_funcs[] =
 {
        {"d0_blind_id_new", (void **) &qd0_blind_id_new},
@@ -227,6 +229,7 @@ static dllfunction_t d0_blind_id_funcs[] =
        {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN},
        {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
        {"d0_blind_id_sign_with_private_id_sign", (void **) &qd0_blind_id_sign_with_private_id_sign},
+       {"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached},
        {NULL, NULL}
 };
 // end of d0_blind_id interface
@@ -354,37 +357,6 @@ static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
        return (size_t) n;
 }
 
-static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
-{
-       unsigned char i0 = (bytes > 0) ? in[0] : 0;
-       unsigned char i1 = (bytes > 1) ? in[1] : 0;
-       unsigned char i2 = (bytes > 2) ? in[2] : 0;
-       unsigned char o0 = base64[i0 >> 2];
-       unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
-       unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
-       unsigned char o3 = base64[i2 & 077];
-       out[0] = (bytes > 0) ? o0 : '?';
-       out[1] = (bytes > 0) ? o1 : '?';
-       out[2] = (bytes > 1) ? o2 : '=';
-       out[3] = (bytes > 2) ? o3 : '=';
-}
-
-size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
-{
-       size_t blocks, i;
-       // expand the out-buffer
-       blocks = (buflen + 2) / 3;
-       if(blocks*4 > outbuflen)
-               return 0;
-       for(i = blocks; i > 0; )
-       {
-               --i;
-               base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);
-       }
-       return blocks * 4;
-}
-
 static qboolean PutWithNul(char **data, size_t *len, const char *str)
 {
        // invariant: data points to insertion point
@@ -1213,7 +1185,7 @@ static void Crypto_Keys_f(void)
                {
                        Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
                        if(pubkeys_havepriv[i])
-                               Con_Printf("   private key key_%d.d0si (fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
+                               Con_Printf("    private ID key_%d.d0si (fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
                }
        }
 }
@@ -1337,9 +1309,14 @@ static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *d
        }
 }
 
+// NOTE: we MUST avoid the following begins of the packet:
+//   1. 0xFF, 0xFF, 0xFF, 0xFF
+//   2. 0x80, 0x00, length/256, length%256
+// this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F
 const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
 {
        unsigned char h[32];
+       int i;
        if(crypto->authenticated)
        {
                if(crypto->use_aes)
@@ -1374,6 +1351,15 @@ const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t
                        *len_dst = len_src + 16;
                        memcpy(data_dst, h, 16);
                        memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
+
+                       // handle the "avoid" conditions:
+                       i = BuffBigLong((unsigned char *) data_dst);
+                       if(
+                               (i == (int)0xFFFFFFFF) // avoid QW control packet
+                               ||
+                               (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet
+                       )
+                               *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it
                }
                return data_dst;
        }
@@ -1387,6 +1373,17 @@ const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t
 const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
 {
        unsigned char h[32];
+       int i;
+
+       // silently handle non-crypto packets
+       i = BuffBigLong((unsigned char *) data_src);
+       if(
+               (i == (int)0xFFFFFFFF) // avoid QW control packet
+               ||
+               (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet
+       )
+               return NULL;
+
        if(crypto->authenticated)
        {
                if(crypto->use_aes)
@@ -1441,11 +1438,31 @@ const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t
                                Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
                                return NULL;
                        }
+
                        if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
                        {
-                               Con_Printf("HMAC mismatch\n");
-                               Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
-                               return NULL;
+                               // undo the "avoid conditions"
+                               if(
+                                               (i == (int)0x7FFFFFFF) // avoided QW control packet
+                                               ||
+                                               (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet
+                                 )
+                               {
+                                       // do the avoidance on the hash too
+                                       h[0] ^= 0x80;
+                                       if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
+                                       {
+                                               Con_Printf("HMAC mismatch\n");
+                                               Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
+                                               return NULL;
+                                       }
+                               }
+                               else
+                               {
+                                       Con_Printf("HMAC mismatch\n");
+                                       Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
+                                       return NULL;
+                               }
                        }
                        return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
                }
@@ -2367,7 +2384,18 @@ size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signe
                return 0;
        if(!pubkeys_havepriv[keyid])
                return 0;
-       if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (char *)data, datasize, (char *)signed_data, &signed_size))
+       if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
+               return signed_size;
+       return 0;
+}
+
+size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
+{
+       if(keyid < 0 || keyid >= MAX_PUBKEYS)
+               return 0;
+       if(!pubkeys_havepriv[keyid])
+               return 0;
+       if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
                return signed_size;
        return 0;
 }