diff --git a/src/lua/box_net_box.lua b/src/lua/box_net_box.lua
index 31adf5785d1554d29c043a1c705cd1bf9f52bc89..953d3f4ef4c9c2a41b138adc528d52c6b0f0ff41 100644
--- a/src/lua/box_net_box.lua
+++ b/src/lua/box_net_box.lua
@@ -39,12 +39,6 @@ local GREETING_SIZE     = 128
 
 local TIMEOUT_INFINITY  = 500 * 365 * 86400
 
-
-ffi.cdef[[
-    int base64_decode(const char *in_base64, int in_len,
-                  char *out_bin, int out_len);
-]]
-
 local sequence_mt = { __serialize = 'sequence'}
 local mapping_mt = { __serialize = 'mapping'}
 
@@ -75,13 +69,6 @@ local function strxor(s1, s2)
     return res
 end
 
-local function b64decode(str)
-    local so = ffi.new('char[?]', string.len(str) * 2);
-    local len =
-        ffi.C.base64_decode(str, string.len(str), so, string.len(str) * 2)
-    return ffi.string(so, len)
-end
-
 local function keyfy(v)
     if type(v) == 'table' then
         return v
@@ -215,7 +202,7 @@ local proto = {
 
     auth = function(sync, user, password, handshake)
         local saltb64 = string.sub(handshake, 65)
-        local salt = string.sub(b64decode(saltb64), 1, 20)
+        local salt = string.sub(digest.base64_decode(saltb64), 1, 20)
 
         local hpassword = digest.sha1(password)
         local hhpassword = digest.sha1(hpassword)
@@ -228,7 +215,7 @@ local proto = {
         )
     end,
 
-    b64decode = b64decode,
+    b64decode = digest.base64_decode,
 }
 
 
diff --git a/src/lua/digest.lua b/src/lua/digest.lua
index 41b28f30b69c3ea537d2596b396e8f351e90e647..3ed17ae92d24c7685bdbed77300d53679daceeff 100644
--- a/src/lua/digest.lua
+++ b/src/lua/digest.lua
@@ -25,6 +25,10 @@ ffi.cdef[[
     typedef uint32_t (*crc32_func)(uint32_t crc,
         const unsigned char *buf, unsigned int len);
     extern crc32_func crc32_calc;
+
+   /* base64 */
+   int base64_decode(const char *in_base64, int in_len, char *out_bin, int out_len);
+   int base64_encode(const char *in_bin, int in_len, char *out_base64, int out_len);
 ]]
 
 local ssl
@@ -67,6 +71,37 @@ local function tohex(r, size)
 end
 
 local m = {
+    base64_encode = function(bin)
+        if bin == nil then
+            bin = ''
+        else
+            -- note: need add check size of bin, bin might containe any binary data
+            if type(bin) == 'string' then
+                local blen = string.len(bin)
+                local slen = math.ceil(blen * 4 / 3) + 1
+                local so  = ffi.new('char[?]', slen)
+                local len = ffi.C.base64_encode(bin, blen, so, slen)
+                bin = ffi.string(so, len)
+            else
+                bin = ''
+            end
+        end
+        return bin
+    end,
+
+    base64_decode = function(data)
+        if type(data) ~= 'string' then
+            data = ''
+        else
+            local slen = string.len(data)
+            local blen = math.ceil((slen - 1) * 4 / 3)
+            local bo  = ffi.new('char[?]', blen)
+            local len = ffi.C.base64_decode(data, slen, bo, blen)
+            data = ffi.string(bo, len)
+        end
+        return data
+    end,
+
     crc32 = function(str)
         if str == nil then
             str = ''
diff --git a/test/box/digest.result b/test/box/digest.result
index 4ee42a1f2098208c350c09789214312c3d4a3e99..81d2414971e673832c161857689b93cadc5fcdf0 100644
--- a/test/box/digest.result
+++ b/test/box/digest.result
@@ -149,6 +149,14 @@ digest.crc32_update(digest.crc32('abc'), 'cde')
 ---
 - 3628146660
 ...
+digest.base64_encode('12345')
+---
+- MTIzNDU=
+...
+digest.base64_decode('MTIzNDU=')
+---
+- '12345'
+...
 digest = nil
 ---
 ...
diff --git a/test/box/digest.test.lua b/test/box/digest.test.lua
index 96f3b5c6d2aa1fb014a79a2e900d50bb1cbb05f4..cc63c16280d5a2c002a91a832042ef1380c310b5 100644
--- a/test/box/digest.test.lua
+++ b/test/box/digest.test.lua
@@ -43,4 +43,7 @@ digest.crc32_update(4294967295, 'abc')
 
 digest.crc32('abccde')
 digest.crc32_update(digest.crc32('abc'), 'cde')
+
+digest.base64_encode('12345')
+digest.base64_decode('MTIzNDU=')
 digest = nil