about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-09T14·09+0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-10T10·33+0100
commita596c525ad3ca86226cdb8094b91a578b23c1dae (patch)
tree04e09211da695cc2d2d72eac119be18dbd370c1c /src
parent70cae879e3c3f5c3fba906ba5ec220f84cff1d61 (diff)
Add base64 encoder/decoder
Diffstat (limited to 'src')
-rw-r--r--src/libutil/util.cc59
-rw-r--r--src/libutil/util.hh5
-rw-r--r--src/nix-store/nix-store.cc10
3 files changed, 66 insertions, 8 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 4f3010880286..be0a9bf317d1 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -1208,4 +1208,63 @@ string filterANSIEscapes(const string & s, bool nixOnly)
 }
 
 
+static char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+string base64Encode(const string & s)
+{
+    string res;
+    int data = 0, nbits = 0;
+
+    for (char c : s) {
+        data = data << 8 | (unsigned char) c;
+        nbits += 8;
+        while (nbits >= 6) {
+            nbits -= 6;
+            res.push_back(base64Chars[data >> nbits & 0x3f]);
+        }
+    }
+
+    if (nbits) res.push_back(base64Chars[data << (6 - nbits) & 0x3f]);
+    while (res.size() % 4) res.push_back('=');
+
+    return res;
+}
+
+
+string base64Decode(const string & s)
+{
+    bool init = false;
+    char decode[256];
+    if (!init) {
+        // FIXME: not thread-safe.
+        memset(decode, -1, sizeof(decode));
+        for (int i = 0; i < 64; i++)
+            decode[(int) base64Chars[i]] = i;
+        init = true;
+    }
+
+    string res;
+    unsigned int d = 0, bits = 0;
+
+    for (char c : s) {
+        if (c == '=') break;
+        if (c == '\n') continue;
+
+        char digit = decode[(unsigned char) c];
+        if (digit == -1)
+            throw Error("invalid character in Base64 string");
+
+        bits += 6;
+        d = d << 6 | digit;
+        if (bits >= 8) {
+            res.push_back(d >> (bits - 8) & 0xff);
+            bits -= 8;
+        }
+    }
+
+    return res;
+}
+
+
 }
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 1a2dda527121..20330fb7699e 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -398,4 +398,9 @@ void ignoreException();
 string filterANSIEscapes(const string & s, bool nixOnly = false);
 
 
+/* Base64 encoding/decoding. */
+string base64Encode(const string & s);
+string base64Decode(const string & s);
+
+
 }
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 18739736838e..c59eb21fb456 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -1023,14 +1023,8 @@ static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
     if (crypto_sign_keypair(pk, sk) != 0)
         throw Error("key generation failed");
 
-    // FIXME: super ugly way to do base64 encoding.
-    auto args = Strings({"-MMIME::Base64", "-0777", "-ne", "print encode_base64($_, '')"});
-
-    string pk64 = runProgram("perl", true, args, string((char *) pk, crypto_sign_PUBLICKEYBYTES));
-    std::cout << keyName << ":" << pk64 << std::endl;
-
-    string sk64 = runProgram("perl", true, args, string((char *) sk, crypto_sign_SECRETKEYBYTES));
-    std::cout << keyName << ":" << sk64 << std::endl;
+    std::cout << keyName << ":" << base64Encode(string((char *) pk, crypto_sign_PUBLICKEYBYTES)) << std::endl;
+    std::cout << keyName << ":" << base64Encode(string((char *) sk, crypto_sign_SECRETKEYBYTES)) << std::endl;
 }