package helpers const b64encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" // Base64Encode encodes bytes to standard base64. The output size is known // from the input size, so it is presized and written through a cursor: push // does not grow, and the padding concat returned a full slice that the next // push could not extend. func Base64Encode(data []byte) (s string) { n := len(data) out := []byte{:(n + 2) / 3 * 4} j := 0 for i := 0; i < n; i += 3 { var b0, b1, b2 byte b0 = data[i] if i+1 < n { b1 = data[i+1] } if i+2 < n { b2 = data[i+2] } out[j] = b64encode[(b0>>2)&0x3f] j++ out[j] = b64encode[((b0<<4)|(b1>>4))&0x3f] j++ if i+1 < n { out[j] = b64encode[((b1<<2)|(b2>>6))&0x3f] } else { out[j] = '=' } j++ if i+2 < n { out[j] = b64encode[b2&0x3f] } else { out[j] = '=' } j++ } return string(out) } // Base64Decode decodes standard base64. Returns nil on invalid input. func Base64Decode(s string) (buf []byte) { // Strip padding. n := len(s) pad := 0 for n > 0 && s[n-1] == '=' { pad++ n-- } out := []byte{:n * 3 / 4} j := 0 var acc uint32 var bits int32 for i := 0; i < n; i++ { v := b64val(s[i]) if v < 0 { return nil } acc = (acc << 6) | uint32(v) bits += 6 if bits >= 8 { bits -= 8 out[j] = byte(acc >> uint32(bits)) j++ } } _ = pad return out[:j] } func b64val(c byte) (n int32) { switch { case c >= 'A' && c <= 'Z': return int32(c - 'A') case c >= 'a' && c <= 'z': return int32(c-'a') + 26 case c >= '0' && c <= '9': return int32(c-'0') + 52 case c == '+': return 62 case c == '/': return 63 default: return -1 } }