// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package base32 implements base32 encoding as specified by RFC 4648.
package base32 import ( ) /* * Encodings */ // An Encoding is a radix 32 encoding/decoding scheme, defined by a // 32-character alphabet. The most common is the "base32" encoding // introduced for SASL GSSAPI and standardized in RFC 4648. // The alternate "base32hex" encoding is used in DNSSEC. type Encoding struct { encode [32]byte // mapping of symbol index to symbol byte value decodeMap [256]uint8 // mapping of symbol byte value to symbol index padChar rune } const ( StdPadding rune = '=' // Standard padding character NoPadding rune = -1 // No padding ) const ( decodeMapInitialize = "" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" invalidIndex = '\xff' ) // NewEncoding returns a new padded Encoding defined by the given alphabet, // which must be a 32-byte string that contains unique byte values and // does not contain the padding character or CR / LF ('\r', '\n'). // The alphabet is treated as a sequence of byte values // without any special treatment for multi-byte UTF-8. // The resulting Encoding uses the default padding character ('='), // which may be changed or disabled via [Encoding.WithPadding]. func ( string) *Encoding { if len() != 32 { panic("encoding alphabet is not 32-bytes long") } := new(Encoding) .padChar = StdPadding copy(.encode[:], ) copy(.decodeMap[:], decodeMapInitialize) for := 0; < len(); ++ { // Note: While we document that the alphabet cannot contain // the padding character, we do not enforce it since we do not know // if the caller intends to switch the padding from StdPadding later. switch { case [] == '\n' || [] == '\r': panic("encoding alphabet contains newline character") case .decodeMap[[]] != invalidIndex: panic("encoding alphabet includes duplicate symbols") } .decodeMap[[]] = uint8() } return } // StdEncoding is the standard base32 encoding, as defined in RFC 4648. var StdEncoding = NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") // HexEncoding is the “Extended Hex Alphabet” defined in RFC 4648. // It is typically used in DNS. var HexEncoding = NewEncoding("0123456789ABCDEFGHIJKLMNOPQRSTUV") // WithPadding creates a new encoding identical to enc except // with a specified padding character, or NoPadding to disable padding. // The padding character must not be '\r' or '\n', // must not be contained in the encoding's alphabet, // must not be negative, and must be a rune equal or below '\xff'. // Padding characters above '\x7f' are encoded as their exact byte value // rather than using the UTF-8 representation of the codepoint. func ( Encoding) ( rune) *Encoding { switch { case < NoPadding || == '\r' || == '\n' || > 0xff: panic("invalid padding") case != NoPadding && .decodeMap[byte()] != invalidIndex: panic("padding contained in alphabet") } .padChar = return & } /* * Encoder */ // Encode encodes src using the encoding enc, // writing [Encoding.EncodedLen](len(src)) bytes to dst. // // The encoding pads the output to a multiple of 8 bytes, // so Encode is not appropriate for use on individual blocks // of a large data stream. Use [NewEncoder] instead. func ( *Encoding) (, []byte) { if len() == 0 { return } // enc is a pointer receiver, so the use of enc.encode within the hot // loop below means a nil check at every operation. Lift that nil check // outside of the loop to speed up the encoder. _ = .encode , := 0, 0 := (len() / 5) * 5 for < { // Combining two 32 bit loads allows the same code to be used // for 32 and 64 bit platforms. := uint32([+0])<<24 | uint32([+1])<<16 | uint32([+2])<<8 | uint32([+3]) := <<8 | uint32([+4]) [+0] = .encode[(>>27)&0x1F] [+1] = .encode[(>>22)&0x1F] [+2] = .encode[(>>17)&0x1F] [+3] = .encode[(>>12)&0x1F] [+4] = .encode[(>>7)&0x1F] [+5] = .encode[(>>2)&0x1F] [+6] = .encode[(>>5)&0x1F] [+7] = .encode[()&0x1F] += 5 += 8 } // Add the remaining small block := len() - if == 0 { return } // Encode the remaining bytes in reverse order. := uint32(0) switch { case 4: |= uint32([+3]) [+6] = .encode[<<3&0x1F] [+5] = .encode[>>2&0x1F] fallthrough case 3: |= uint32([+2]) << 8 [+4] = .encode[>>7&0x1F] fallthrough case 2: |= uint32([+1]) << 16 [+3] = .encode[>>12&0x1F] [+2] = .encode[>>17&0x1F] fallthrough case 1: |= uint32([+0]) << 24 [+1] = .encode[>>22&0x1F] [+0] = .encode[>>27&0x1F] } // Pad the final quantum if .padChar != NoPadding { := ( * 8 / 5) + 1 for := ; < 8; ++ { [+] = byte(.padChar) } } } // AppendEncode appends the base32 encoded src to dst // and returns the extended buffer. func ( *Encoding) (, []byte) []byte { := .EncodedLen(len()) = slices.Grow(, ) .Encode([len():][:], ) return [:len()+] } // EncodeToString returns the base32 encoding of src. func ( *Encoding) ( []byte) string { := make([]byte, .EncodedLen(len())) .Encode(, ) return string() } type encoder struct { err error enc *Encoding w io.Writer buf [5]byte // buffered data waiting to be encoded nbuf int // number of bytes in buf out [1024]byte // output buffer } func ( *encoder) ( []byte) ( int, error) { if .err != nil { return 0, .err } // Leading fringe. if .nbuf > 0 { var int for = 0; < len() && .nbuf < 5; ++ { .buf[.nbuf] = [] .nbuf++ } += = [:] if .nbuf < 5 { return } .enc.Encode(.out[0:], .buf[0:]) if _, .err = .w.Write(.out[0:8]); .err != nil { return , .err } .nbuf = 0 } // Large interior chunks. for len() >= 5 { := len(.out) / 8 * 5 if > len() { = len() -= % 5 } .enc.Encode(.out[0:], [0:]) if _, .err = .w.Write(.out[0 : /5*8]); .err != nil { return , .err } += = [:] } // Trailing fringe. copy(.buf[:], ) .nbuf = len() += len() return } // Close flushes any pending output from the encoder. // It is an error to call Write after calling Close. func ( *encoder) () error { // If there's anything left in the buffer, flush it out if .err == nil && .nbuf > 0 { .enc.Encode(.out[0:], .buf[0:.nbuf]) := .enc.EncodedLen(.nbuf) .nbuf = 0 _, .err = .w.Write(.out[0:]) } return .err } // NewEncoder returns a new base32 stream encoder. Data written to // the returned writer will be encoded using enc and then written to w. // Base32 encodings operate in 5-byte blocks; when finished // writing, the caller must Close the returned encoder to flush any // partially written blocks. func ( *Encoding, io.Writer) io.WriteCloser { return &encoder{enc: , w: } } // EncodedLen returns the length in bytes of the base32 encoding // of an input buffer of length n. func ( *Encoding) ( int) int { if .padChar == NoPadding { return /5*8 + (%5*8+4)/5 } return ( + 4) / 5 * 8 } /* * Decoder */ type CorruptInputError int64 func ( CorruptInputError) () string { return "illegal base32 data at input byte " + strconv.FormatInt(int64(), 10) } // decode is like Decode but returns an additional 'end' value, which // indicates if end-of-message padding was encountered and thus any // additional data is an error. This method assumes that src has been // stripped of all supported whitespace ('\r' and '\n'). func ( *Encoding) (, []byte) ( int, bool, error) { // Lift the nil check outside of the loop. _ = .decodeMap := 0 := len() for len() > 0 && ! { // Decode quantum using the base32 alphabet var [8]byte := 8 for := 0; < 8; { if len() == 0 { if .padChar != NoPadding { // We have reached the end and are missing padding return , false, CorruptInputError( - len() - ) } // We have reached the end and are not expecting any padding , = , true break } := [0] = [1:] if == byte(.padChar) && >= 2 && len() < 8 { // We've reached the end and there's padding if len()+ < 8-1 { // not enough padding return , false, CorruptInputError() } for := 0; < 8-1-; ++ { if len() > && [] != byte(.padChar) { // incorrect padding return , false, CorruptInputError( - len() + - 1) } } , = , true // 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not // valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing // the five valid padding lengths, and Section 9 "Illustrations and // Examples" for an illustration for how the 1st, 3rd and 6th base32 // src bytes do not yield enough information to decode a dst byte. if == 1 || == 3 || == 6 { return , false, CorruptInputError( - len() - 1) } break } [] = .decodeMap[] if [] == 0xFF { return , false, CorruptInputError( - len() - 1) } ++ } // Pack 8x 5-bit source blocks into 5 byte destination // quantum switch { case 8: [+4] = [6]<<5 | [7] ++ fallthrough case 7: [+3] = [4]<<7 | [5]<<2 | [6]>>3 ++ fallthrough case 5: [+2] = [3]<<4 | [4]>>1 ++ fallthrough case 4: [+1] = [1]<<6 | [2]<<1 | [3]>>4 ++ fallthrough case 2: [+0] = [0]<<3 | [1]>>2 ++ } += 5 } return , , nil } // Decode decodes src using the encoding enc. It writes at most // [Encoding.DecodedLen](len(src)) bytes to dst and returns the number of bytes // written. If src contains invalid base32 data, it will return the // number of bytes successfully written and [CorruptInputError]. // Newline characters (\r and \n) are ignored. func ( *Encoding) (, []byte) ( int, error) { := make([]byte, len()) := stripNewlines(, ) , _, = .decode(, [:]) return } // AppendDecode appends the base32 decoded src to dst // and returns the extended buffer. // If the input is malformed, it returns the partially decoded src and an error. func ( *Encoding) (, []byte) ([]byte, error) { // Compute the output size without padding to avoid over allocating. := len() for > 0 && rune([-1]) == .padChar { -- } = decodedLen(, NoPadding) = slices.Grow(, ) , := .Decode([len():][:], ) return [:len()+], } // DecodeString returns the bytes represented by the base32 string s. func ( *Encoding) ( string) ([]byte, error) { := []byte() := stripNewlines(, ) , , := .decode(, [:]) return [:], } type decoder struct { err error enc *Encoding r io.Reader end bool // saw end of message buf [1024]byte // leftover input nbuf int out []byte // leftover decoded output outbuf [1024 / 8 * 5]byte } func readEncodedData( io.Reader, []byte, int, bool) ( int, error) { for < && == nil { var int , = .Read([:]) += } // data was read, less than min bytes could be read if < && > 0 && == io.EOF { = io.ErrUnexpectedEOF } // no data was read, the buffer already contains some data // when padding is disabled this is not an error, as the message can be of // any length if && < 8 && == 0 && == io.EOF { = io.ErrUnexpectedEOF } return } func ( *decoder) ( []byte) ( int, error) { // Use leftover decoded output from last read. if len(.out) > 0 { = copy(, .out) .out = .out[:] if len(.out) == 0 { return , .err } return , nil } if .err != nil { return 0, .err } // Read a chunk. := (len() + 4) / 5 * 8 if < 8 { = 8 } if > len(.buf) { = len(.buf) } // Minimum amount of bytes that needs to be read each cycle var int var bool if .enc.padChar == NoPadding { = 1 = false } else { = 8 - .nbuf = true } , .err = readEncodedData(.r, .buf[.nbuf:], , ) .nbuf += if .nbuf < { return 0, .err } if > 0 && .end { return 0, CorruptInputError(0) } // Decode chunk into p, or d.out and then p if p is too small. var int if .enc.padChar == NoPadding { = .nbuf } else { = .nbuf / 8 * 8 } := .enc.DecodedLen(.nbuf) if > len() { , .end, = .enc.decode(.outbuf[0:], .buf[0:]) .out = .outbuf[0:] = copy(, .out) .out = .out[:] } else { , .end, = .enc.decode(, .buf[0:]) } .nbuf -= for := 0; < .nbuf; ++ { .buf[] = .buf[+] } if != nil && (.err == nil || .err == io.EOF) { .err = } if len(.out) > 0 { // We cannot return all the decoded bytes to the caller in this // invocation of Read, so we return a nil error to ensure that Read // will be called again. The error stored in d.err, if any, will be // returned with the last set of decoded bytes. return , nil } return , .err } type newlineFilteringReader struct { wrapped io.Reader } // stripNewlines removes newline characters and returns the number // of non-newline characters copied to dst. func stripNewlines(, []byte) int { := 0 for , := range { if == '\r' || == '\n' { continue } [] = ++ } return } func ( *newlineFilteringReader) ( []byte) (int, error) { , := .wrapped.Read() for > 0 { := [0:] := stripNewlines(, ) if != nil || > 0 { return , } // Previous buffer entirely whitespace, read again , = .wrapped.Read() } return , } // NewDecoder constructs a new base32 stream decoder. func ( *Encoding, io.Reader) io.Reader { return &decoder{enc: , r: &newlineFilteringReader{}} } // DecodedLen returns the maximum length in bytes of the decoded data // corresponding to n bytes of base32-encoded data. func ( *Encoding) ( int) int { return decodedLen(, .padChar) } func decodedLen( int, rune) int { if == NoPadding { return /8*5 + %8*5/8 } return / 8 * 5 }