List:Commits« Previous MessageNext Message »
From:Nirbhay Choubey Date:February 15 2012 10:29am
Subject:bzr push into mysql-trunk branch (nirbhay.choubey:3834 to 3835) WL#6008
View as plain text  
 3835 Nirbhay Choubey	2012-02-15
      WL#6008 : Replace custom encryption code with approved
                encryption packages

    added:
      sql/md5.cc
      sql/sha1.cc
    modified:
      include/my_md5.h
      include/sha1.h
      libmysql/CMakeLists.txt
      mysys/CMakeLists.txt
      mysys/md5.c
      mysys/sha1.c
      sql/CMakeLists.txt
      sql/item_strfunc.cc
      sql/password.c
      sql/table.cc
 3834 Jorgen Loland	2012-02-03
      Assertion that selectivity does not increase by adding another 
      scan to a ROR intersect triggers. Temporarily remove it.

    modified:
      sql/opt_range.cc
=== modified file 'include/my_md5.h'
--- a/include/my_md5.h	2009-09-23 21:32:31 +0000
+++ b/include/my_md5.h	2012-02-15 10:27:24 +0000
@@ -22,6 +22,36 @@
  * $FreeBSD: src/contrib/cvs/lib/md5.h,v 1.2 1999/12/11 15:10:02 peter Exp $
  */
 
+#if defined(HAVE_YASSL) || defined(HAVE_OPENSSL)
+/*
+  Use MD5 implementation provided by the SSL libraries.
+*/
+
+#if defined(HAVE_YASSL)
+
+C_MODE_START
+
+void my_md5_hash(char *digest, const char *buf, int len);
+
+C_MODE_END
+
+#else /* HAVE_YASSL */
+
+#include <openssl/md5.h>
+
+#define MY_MD5_HASH(digest, buf, len) \
+do { \
+  MD5_CTX ctx; \
+  MD5_Init (&ctx); \
+  MD5_Update (&ctx, buf, len); \
+  MD5_Final (digest, &ctx); \
+} while (0)
+
+#endif /* HAVE_YASSL */
+
+#else /* HAVE_YASSL || HAVE_OPENSSL */
+/* Fallback to the MySQL's implementation. */
+
 /* Unlike previous versions of this code, uint32 need not be exactly
    32 bits, merely 32 bits or more.  Choosing a data type which is 32
    bits instead of 64 is not important; speed is considerably more
@@ -35,18 +65,15 @@ typedef struct {
   unsigned char in[64];
 } my_MD5Context;
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+C_MODE_START
+
 void my_MD5Init (my_MD5Context *context);
 void my_MD5Update (my_MD5Context *context,
                    unsigned char const *buf, unsigned len);
 void my_MD5Final (unsigned char digest[16],
                   my_MD5Context *context);
 
-#ifdef __cplusplus
-}
-#endif
+C_MODE_END
 
 #define MY_MD5_HASH(digest,buf,len) \
 do { \
@@ -56,4 +83,12 @@ do { \
   my_MD5Final (digest, &ctx); \
 } while (0)
 
-#endif /* MY_MD__INCLUDED */
+#endif /* defined(HAVE_YASSL) || defined(HAVE_OPENSSL) */
+
+C_MODE_START
+
+void compute_md5_hash(char *digest, const char *buf, int len);
+
+C_MODE_END
+
+#endif /* MY_MD5_INCLUDED */

=== modified file 'include/sha1.h'
--- a/include/sha1.h	2011-06-30 15:46:53 +0000
+++ b/include/sha1.h	2012-02-15 10:27:24 +0000
@@ -64,6 +64,28 @@
   Internet Society. 
 */
 
+#define SHA1_HASH_SIZE 20 /* Hash size in bytes */
+
+/*
+  Use SHA1 implementation provided by the SSL libraries if available.
+*/
+
+#if defined(HAVE_YASSL)
+
+C_MODE_START
+
+void mysql_sha1_yassl(uint8 *digest, const char *buf, int len);
+void mysql_sha1_multi_yassl(uint8 *digest, const char *buf1, int len1,
+                            const char *buf2, int len2);
+
+C_MODE_END
+
+#elif defined(HAVE_OPENSSL)
+
+#include <openssl/sha.h>
+#define SHA1_CONTEXT SHA_CTX
+
+# else
 
 enum sha_result_codes
 {
@@ -73,8 +95,6 @@ enum sha_result_codes
   SHA_STATE_ERROR	/* called Input after Result */
 };
 
-#define SHA1_HASH_SIZE 20 /* Hash size in bytes */
-
 /*
   This structure will hold context information for the SHA-1
   hashing operation
@@ -90,8 +110,11 @@ typedef struct SHA1_CONTEXT
   uint8 Message_Block[64];	/* 512-bit message blocks      */
 } SHA1_CONTEXT;
 
+#endif  /* HAVE_YASSL */
+
+#ifndef HAVE_YASSL
 /*
-  Function Prototypes
+  Function Prototypes (shared by MySQL & OpenSSL's SHA1 implementation )
 */
 
 C_MODE_START
@@ -102,4 +125,14 @@ int mysql_sha1_result(SHA1_CONTEXT* , ui
 
 C_MODE_END
 
-#endif /* SHA__INCLUDED */
+#endif /* HAVE_YASSL */
+
+C_MODE_START
+
+void compute_sha1_hash(uint8 *digest, const char *buf, int len);
+void compute_sha1_hash_multi(uint8 *digest, const char *buf1, int len1,
+                             const char *buf2, int len2);
+
+C_MODE_END
+
+#endif /* SHA1_INCLUDED */

=== modified file 'libmysql/CMakeLists.txt'
--- a/libmysql/CMakeLists.txt	2012-01-30 09:30:13 +0000
+++ b/libmysql/CMakeLists.txt	2012-02-15 10:27:24 +0000
@@ -145,6 +145,8 @@ SET(CLIENT_SOURCES
   ../sql-common/client_plugin.c 
   ../sql/net_serv.cc
   ../sql-common/pack.c 
+  ../sql/md5.cc
+  ../sql/sha1.cc
   ../sql/password.c
 )
 ADD_CONVENIENCE_LIBRARY(clientlib ${CLIENT_SOURCES})

=== modified file 'mysys/CMakeLists.txt'
--- a/mysys/CMakeLists.txt	2011-10-11 04:27:52 +0000
+++ b/mysys/CMakeLists.txt	2012-02-15 10:27:24 +0000
@@ -15,6 +15,10 @@
 
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys)
 
+IF(SSL_DEFINES)
+ADD_DEFINITIONS(${SSL_DEFINES})
+ENDIF()
+
 SET(MYSYS_SOURCES  array.c charset-def.c charset.c checksum.c default.c
 				errors.c hash.c list.c md5.c mf_cache.c mf_dirname.c mf_fn_ext.c
 				mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c 

=== modified file 'mysys/md5.c'
--- a/mysys/md5.c	2009-03-09 18:57:03 +0000
+++ b/mysys/md5.c	2012-02-15 10:27:24 +0000
@@ -38,6 +38,11 @@
    copyright in any changes I have made; this code remains in the
    public domain.  */
 
+/*
+  Skip entirely if built with OpenSSL/YaSSL support.
+*/
+#if !defined(HAVE_OPENSSL) && !defined(HAVE_YASSL)
+
 #include <my_global.h>
 #include <m_string.h>
 #include "my_md5.h"
@@ -323,3 +328,5 @@ main (int argc, char **argv)
   return 0;
 }
 #endif /* TEST */
+
+#endif /* !defined(HAVE_OPENSSL) && !defined(HAVE_YASSL) */

=== modified file 'mysys/sha1.c'
--- a/mysys/sha1.c	2011-06-30 15:50:45 +0000
+++ b/mysys/sha1.c	2012-02-15 10:27:24 +0000
@@ -84,6 +84,41 @@
 #include "sha1.h"
 
 /*
+  Skip entire file if built with YaSSL.
+*/
+#ifndef HAVE_YASSL
+
+#ifdef HAVE_OPENSSL
+
+/*
+  Wrapper for OpenSSL SH1 methods.
+*/
+
+int mysql_sha1_reset(SHA1_CONTEXT *context)
+{
+  return SHA1_Init(context);
+}
+
+
+int mysql_sha1_input(SHA1_CONTEXT *context, const uint8 *message_array,
+                     unsigned length)
+{
+  return SHA1_Update(context, message_array, length);
+}
+
+
+int mysql_sha1_result(SHA1_CONTEXT *context,
+                      uint8 Message_Digest[SHA1_HASH_SIZE])
+{
+  return SHA1_Final(Message_Digest, context);
+}
+
+#else /* HAVE_OPENSSL */
+/*
+  Native MySQL SHA1 implementation.
+*/
+
+/*
   Define the SHA1 circular left shift macro
 */
 
@@ -420,3 +455,6 @@ static void SHA1PadMessage(SHA1_CONTEXT 
 
   SHA1ProcessMessageBlock(context);
 }
+#endif /* HAVE_OPENSSL */
+
+#endif /* HAVE_YASSL */

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2012-01-05 10:14:20 +0000
+++ b/sql/CMakeLists.txt	2012-02-15 10:27:24 +0000
@@ -69,6 +69,7 @@ SET(SQL_SHARED_SOURCES
   keycaches.cc
   lock.cc
   log.cc
+  md5.cc
   mdl.cc
   mf_iocache.cc
   my_decimal.cc
@@ -87,6 +88,7 @@ SET(SQL_SHARED_SOURCES
   rpl_handler.cc
   scheduler.cc 
   set_var.cc 
+  sha1.cc
   sha2.cc
   signal_handler.cc
   sp.cc

=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc	2011-12-15 11:54:45 +0000
+++ b/sql/item_strfunc.cc	2012-02-15 10:27:24 +0000
@@ -181,7 +181,7 @@ String *Item_func_md5::val_str_ascii(Str
     uchar digest[16];
 
     null_value=0;
-    MY_MD5_HASH(digest,(uchar *) sptr->ptr(), sptr->length());
+    compute_md5_hash((char *) digest, (const char *) sptr->ptr(), sptr->length());
     if (str->alloc(32))				// Ensure that memory is free
     {
       null_value=1;
@@ -217,16 +217,11 @@ String *Item_func_sha::val_str_ascii(Str
   str->set_charset(&my_charset_bin);
   if (sptr)  /* If we got value different from NULL */
   {
-    SHA1_CONTEXT context;  /* Context used to generate SHA1 hash */
     /* Temporary buffer to store 160bit digest */
     uint8 digest[SHA1_HASH_SIZE];
-    mysql_sha1_reset(&context);  /* We do not have to check for error here */
-    /* No need to check error as the only case would be too long message */
-    mysql_sha1_input(&context,
-                     (const uchar *) sptr->ptr(), sptr->length());
-    /* Ensure that memory is free and we got result */
-    if (!( str->alloc(SHA1_HASH_SIZE*2) ||
-           (mysql_sha1_result(&context,digest))))
+    compute_sha1_hash(digest, (const char *) sptr->ptr(), sptr->length());
+    /* Ensure that memory is free */
+    if (!(str->alloc(SHA1_HASH_SIZE * 2)))
     {
       array_to_hex((char *) str->ptr(), digest, SHA1_HASH_SIZE);
       str->length((uint)  SHA1_HASH_SIZE*2);

=== added file 'sql/md5.cc'
--- a/sql/md5.cc	1970-01-01 00:00:00 +0000
+++ b/sql/md5.cc	2012-02-15 10:27:24 +0000
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+  @file
+
+  @brief
+  Wrapper functions for OpenSSL, YaSSL and MySQL's MD5
+  implementations. Also provides a Compatibility layer
+  to make available YaSSL's MD5 implementation.
+*/
+
+#include <my_global.h>
+#include <my_md5.h>
+
+#ifdef HAVE_YASSL
+
+#include "md5.hpp"
+
+/**
+  Compute MD5 message digest.
+
+  @param digest [out]  Computed MD5 digest
+  @param buf    [in]   Message to be computed
+  @param len    [in]   Length of the message
+
+  @return              void
+*/
+void my_md5_hash(char *digest, const char *buf, int len)
+{
+  TaoCrypt::MD5 hasher;
+  hasher.Update((TaoCrypt::byte *) buf, len);
+  hasher.Final((TaoCrypt::byte *) digest);
+}
+#endif /* HAVE_YASSL */
+
+
+/**
+    Wrapper function to compute MD5 message digest.
+
+    @param digest [out]  Computed MD5 digest
+    @param buf    [in]   Message to be computed
+    @param len    [in]   Length of the message
+
+    @return              void
+*/
+void compute_md5_hash(char *digest, const char *buf, int len)
+{
+#ifdef HAVE_YASSL
+  my_md5_hash(digest, buf, len);
+#else
+  MY_MD5_HASH((unsigned char *) digest, (unsigned char const *) buf, len);
+#endif /* HAVE_YASSL */
+}
+

=== modified file 'sql/password.c'
--- a/sql/password.c	2011-07-04 00:25:46 +0000
+++ b/sql/password.c	2012-02-15 10:27:24 +0000
@@ -398,6 +398,29 @@ my_crypt(char *to, const uchar *s1, cons
     *to++= *s1++ ^ *s2++;
 }
 
+/**
+  Compute two stage SHA1 hash of the password :
+
+    hash_stage1=sha1("password")
+    hash_stage2=sha1(hash_stage1)
+
+  @param password    [IN]   Password string.
+  @param pass_len    [IN]   Length of the password.
+  @param hash_stage1 [OUT]  sha1(password)
+  @param hash_stage2 [OUT]  sha1(hash_stage1)
+*/
+
+inline static
+void compute_two_stage_sha1_hash(const char *password, size_t pass_len,
+                                 uint8 *hash_stage1, uint8 *hash_stage2)
+{
+  /* Stage 1: hash password */
+  compute_sha1_hash(hash_stage1, password, pass_len);
+
+  /* Stage 2 : hash first stage's output. */
+  compute_sha1_hash(hash_stage2, (const char *) hash_stage1, SHA1_HASH_SIZE);
+}
+
 
 /*
     MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
@@ -415,18 +438,11 @@ my_crypt(char *to, const uchar *s1, cons
 void my_make_scrambled_password(char *to, const char *password,
                                 size_t pass_len)
 {
-  SHA1_CONTEXT sha1_context;
   uint8 hash_stage2[SHA1_HASH_SIZE];
 
-  mysql_sha1_reset(&sha1_context);
-  /* stage 1: hash password */
-  mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) pass_len);
-  mysql_sha1_result(&sha1_context, (uint8 *) to);
-  /* stage 2: hash stage1 output */
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE);
-  /* separate buffer is used to pass 'to' in octet2hex */
-  mysql_sha1_result(&sha1_context, hash_stage2);
+  /* Two stage SHA1 hash of the password. */
+  compute_two_stage_sha1_hash(password, pass_len, (uint8 *) to, hash_stage2);
+
   /* convert hash_stage2 to hex string */
   *to++= PVERSION41_CHAR;
   octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
@@ -470,24 +486,16 @@ void make_scrambled_password(char *to, c
 void
 scramble(char *to, const char *message, const char *password)
 {
-  SHA1_CONTEXT sha1_context;
   uint8 hash_stage1[SHA1_HASH_SIZE];
   uint8 hash_stage2[SHA1_HASH_SIZE];
 
-  mysql_sha1_reset(&sha1_context);
-  /* stage 1: hash password */
-  mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
-  mysql_sha1_result(&sha1_context, hash_stage1);
-  /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE);
-  mysql_sha1_result(&sha1_context, hash_stage2);
+  /* Two stage SHA1 hash of the password. */
+  compute_two_stage_sha1_hash(password, strlen(password), hash_stage1,
+                              hash_stage2);
+
   /* create crypt string as sha1(message, hash_stage2) */;
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
-  mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
-  /* xor allows 'from' and 'to' overlap: lets take advantage of it */
-  mysql_sha1_result(&sha1_context, (uint8 *) to);
+  compute_sha1_hash_multi((uint8 *) to, message, SCRAMBLE_LENGTH,
+                          (const char *) hash_stage2, SHA1_HASH_SIZE);
   my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH);
 }
 
@@ -516,21 +524,18 @@ my_bool
 check_scramble(const uchar *scramble_arg, const char *message,
                const uint8 *hash_stage2)
 {
-  SHA1_CONTEXT sha1_context;
   uint8 buf[SHA1_HASH_SIZE];
   uint8 hash_stage2_reassured[SHA1_HASH_SIZE];
 
-  mysql_sha1_reset(&sha1_context);
   /* create key to encrypt scramble */
-  mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
-  mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
-  mysql_sha1_result(&sha1_context, buf);
+  compute_sha1_hash_multi(buf, message, SCRAMBLE_LENGTH,
+                          (const char *) hash_stage2, SHA1_HASH_SIZE);
   /* encrypt scramble */
-    my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
+  my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
+
   /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
-  mysql_sha1_reset(&sha1_context);
-  mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
-  mysql_sha1_result(&sha1_context, hash_stage2_reassured);
+  compute_sha1_hash(hash_stage2_reassured, (const char *) buf, SHA1_HASH_SIZE);
+
   return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
 }
 

=== added file 'sql/sha1.cc'
--- a/sql/sha1.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sha1.cc	2012-02-15 10:27:24 +0000
@@ -0,0 +1,121 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+
+/**
+  @file
+
+  @brief
+  Wrapper functions for OpenSSL, YaSSL and MySQL's SHA1
+  implementations. Also provides a Compatibility layer
+  to make available YaSSL's SHA1 implementation.
+*/
+
+#include <my_global.h>
+#include <sha1.h>
+
+#ifdef HAVE_YASSL
+#include "sha.hpp"
+
+/**
+  Compute SHA1 message digest using YaSSL.
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf    [in]   Message to be computed
+  @param len    [in]   Length of the message
+
+  @return              void
+*/
+void mysql_sha1_yassl(uint8 *digest, const char *buf, int len)
+{
+  TaoCrypt::SHA hasher;
+  hasher.Update((const TaoCrypt::byte *) buf, len);
+  hasher.Final ((TaoCrypt::byte *) digest);
+}
+
+/**
+  Compute SHA1 message digest for two messages in order to
+  emulate sha1(msg1, msg2) using YaSSL.
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf1   [in]   First message
+  @param len1   [in]   Length of first message
+  @param buf2   [in]   Second message
+  @param len2   [in]   Length of second message
+
+  @return              void
+*/
+void mysql_sha1_multi_yassl(uint8 *digest, const char *buf1, int len1,
+                            const char *buf2, int len2)
+{
+  TaoCrypt::SHA hasher;
+  hasher.Update((const TaoCrypt::byte *) buf1, len1);
+  hasher.Update((const TaoCrypt::byte *) buf2, len2);
+  hasher.Final((TaoCrypt::byte *) digest);
+}
+
+#endif /* HAVE_YASSL */
+
+
+/**
+  Wrapper function to compute SHA1 message digest.
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf    [in]   Message to be computed
+  @param len    [in]   Length of the message
+
+  @return              void
+*/
+void compute_sha1_hash(uint8 *digest, const char *buf, int len)
+{
+#ifdef HAVE_YASSL
+  mysql_sha1_yassl(digest, buf, len);
+#else
+  SHA1_CONTEXT sha1_context;
+
+  mysql_sha1_reset(&sha1_context);
+  mysql_sha1_input(&sha1_context, (const uint8 *) buf, len);
+  mysql_sha1_result(&sha1_context, digest);
+#endif /* HAVE_YASSL */
+}
+
+
+/**
+  Wrapper function to compute SHA1 message digest for
+  two messages in order to emulate sha1(msg1, msg2).
+
+  @param digest [out]  Computed SHA1 digest
+  @param buf1   [in]   First message
+  @param len1   [in]   Length of first message
+  @param buf2   [in]   Second message
+  @param len2   [in]   Length of second message
+
+  @return              void
+*/
+void compute_sha1_hash_multi(uint8 *digest, const char *buf1, int len1,
+                             const char *buf2, int len2)
+{
+#ifdef HAVE_YASSL
+  mysql_sha1_multi_yassl(digest, buf1, len1, buf2, len2);
+#else
+  SHA1_CONTEXT sha1_context;
+
+  mysql_sha1_reset(&sha1_context);
+  mysql_sha1_input(&sha1_context, (const uint8 *) buf1, len1);
+  mysql_sha1_input(&sha1_context, (const uint8 *) buf2, len2);
+  mysql_sha1_result(&sha1_context, digest);
+#endif /* HAVE_YASSL */
+}
+

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2012-01-31 15:16:16 +0000
+++ b/sql/table.cc	2012-02-15 10:27:24 +0000
@@ -3532,7 +3532,8 @@ void TABLE::reset_item_list(List<Item> *
 void  TABLE_LIST::calc_md5(char *buffer)
 {
   uchar digest[16];
-  MY_MD5_HASH(digest, (uchar *) select_stmt.str, select_stmt.length);
+  compute_md5_hash((char *) digest, (const char *) select_stmt.str,
+                   select_stmt.length);
   sprintf((char *) buffer,
 	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
 	    digest[0], digest[1], digest[2], digest[3],

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (nirbhay.choubey:3834 to 3835) WL#6008Nirbhay Choubey15 Feb