// Runs this Hash's text child through a base64 decoder and replaces it with // the result. Garbage characters (such as whitespace) are ignored during the // decoding. func (self *Hash) DecodeBase64() { text := self.TextFragments() self.SetText() var carry int for i := range text { self.AppendString(string(util.Base64DecodeString(text[i], &carry))) } flush := string(util.Base64DecodeString("=", &carry)) self.AppendString(flush) }
func (e *base64Eater) Eat(b byte) int { if b <= ' ' || e.status != 0 { // ignore control characters; also exit if we have a status return e.status } carry_old := e.carry decoded := util.Base64DecodeString(string([]byte{b}), &e.carry) if len(decoded) == 0 { if carry_old == e.carry { // no result and no state change => garbage e.status = -1 } } else { for _, dec := range decoded { e.status = e.daisy.Eat(dec) } } return e.status }
// Tries to decrypt msg with the given key and returns the decrypted message or // the empty string if decryption failed. Decryption will be considered successful // if the decrypted message starts with "<xml>" (after trimming whitespace). // // Whitespace will be trimmed at the start and end of msg before decryption. // // msg can be one of the following: // // * an unencrypted message starting (after trimming) with "<xml>". It will be // returned trimmed but otherwise unchanged. // // * a base64 string as returned by GosaEncrypt when used with the same key. // The unencrypted message will be returned. // // The key is a word as used in gosa-si.conf whose md5sum will // be used as the actual AES key. func GosaDecrypt(msg string, key string) string { trimmed := strings.TrimSpace(msg) if strings.HasPrefix(trimmed, "<xml>") { return trimmed } // Fixes the following: // * gosa-si bug in the following line: // if( $client_answer =~ s/session_id=(\d+)$// ) { // This leaves the "." before "session_id" which breaks base64 // * new gosa-si protocol has ";IP:PORT" appended to message // which also breaks base64 semicolon_period := strings.IndexAny(trimmed, ";.") if semicolon_period >= 0 { trimmed = trimmed[:semicolon_period] } cyphertext := util.Base64DecodeString(trimmed, nil) if len(cyphertext)%aes.BlockSize != 0 { return "" } aes, _ := aes.NewCipher([]byte(util.Md5sum(key))) crypter := cipher.NewCBCDecrypter(aes, config.InitializationVector) crypter.CryptBlocks(cyphertext, cyphertext) for len(cyphertext) > 0 && cyphertext[0] == 0 { cyphertext = cyphertext[1:] } for len(cyphertext) > 0 && cyphertext[len(cyphertext)-1] == 0 { cyphertext = cyphertext[:len(cyphertext)-1] } trimmed = strings.TrimSpace(string(cyphertext)) if strings.HasPrefix(trimmed, "<xml>") { return trimmed } return "" }
func testBase64() { check(util.Base64DecodeString("", nil), []byte{}) check(util.Base64DecodeInPlace([]byte{}), []byte{}) check(util.Base64DecodeString("=", nil), []byte{}) check(util.Base64DecodeInPlace([]byte("=")), []byte{}) check(util.Base64DecodeString(" = ", nil), []byte{}) check(util.Base64DecodeInPlace([]byte(" = ")), []byte{}) check(util.Base64DecodeString("/+/+", nil), []byte{0xff, 0xef, 0xfe}) check(util.Base64DecodeInPlace([]byte("/+/+")), []byte{0xff, 0xef, 0xfe}) check(util.Base64DecodeString("_-_-", nil), []byte{0xff, 0xef, 0xfe}) check(util.Base64DecodeInPlace([]byte("_-_-")), []byte{0xff, 0xef, 0xfe}) var devnull int check(string(util.Base64DecodeString("SGFsbG8=", nil)), "Hallo") check(string(util.Base64DecodeInPlace([]byte("SGFsbG8="))), "Hallo") check(string(util.Base64DecodeString("SGFsbA==", nil)), "Hall") check(string(util.Base64DecodeInPlace([]byte("SGFsbA=="))), "Hall") check(string(util.Base64DecodeString("SGFsbG8", nil)), "Hallo") check(string(util.Base64DecodeInPlace([]byte("SGFsbG8"))), "Hallo") check(string(util.Base64DecodeString("SGFsbA=", nil)), "Hall") check(string(util.Base64DecodeInPlace([]byte("SGFsbA="))), "Hall") check(string(util.Base64DecodeString("SGFsbG8===", nil)), "Hallo") check(string(util.Base64DecodeInPlace([]byte("SGFsbG8==="))), "Hallo") check(string(util.Base64DecodeString("SGFsbA", nil)), "Hall") check(string(util.Base64DecodeInPlace([]byte("SGFsbA"))), "Hall") check(string(util.Base64DecodeString("SGFsbG8=", &devnull)), "Hallo") check(devnull, 0) check(string(util.Base64DecodeString("SGFsbA==", &devnull)), "Hall") check(devnull, 0) check(string(util.Base64DecodeString("SGFsbA=", &devnull)), "Hall") check(devnull, 0) check(string(util.Base64DecodeString("SGFsbG8===", &devnull)), "Hallo") check(devnull, 0) check(string(util.Base64DecodeString("AA", nil)), "\000") check(string(util.Base64DecodeInPlace([]byte("AA"))), "\000") check(string(util.Base64DecodeString("AAA", nil)), "\000\000") check(string(util.Base64DecodeInPlace([]byte("AAA"))), "\000\000") var zerocarry int check(string(util.Base64DecodeString("AA", &zerocarry)), "") check(zerocarry != 0, true) check(string(util.Base64DecodeString("=", &zerocarry)), "\000") check(zerocarry, 0) check(string(util.Base64DecodeString("AAA", &zerocarry)), "") check(zerocarry != 0, true) check(string(util.Base64DecodeString("=", &zerocarry)), "\000\000") check(zerocarry, 0) testbuf := make([]byte, 1024) for i := range testbuf { testbuf[i] = byte(i) } error_list := "" for length := 0; length <= 12; length++ { for eq := 0; eq <= 4; eq++ { for err := 0; err <= 12; err++ { b64_1 := base64.StdEncoding.EncodeToString(testbuf[0 : 512-length]) testslice := b64_1[0:] errors := []int{0} for e := 0; e < err; e++ { errors = append(errors, errors[e]+rand.Intn(len(testslice)-errors[e])) } errors = append(errors, len(testslice)) teststr := "" for i := 0; i < len(errors)-1; i++ { if i != 0 { teststr = teststr + "\000\n" } teststr = teststr + testslice[errors[i]:errors[i+1]] } for i := 0; i < eq; i++ { teststr += "=" } // because we're concatenating we need at least 1 "=" if the // first string ends in an incomplete block if eq == 0 && (length&3) != 0 { teststr += "=" } b64_2 := base64.URLEncoding.EncodeToString(testbuf[512-length:]) testslice = b64_2[0:] errors = []int{0} for e := 0; e < err; e++ { errors = append(errors, errors[e]+rand.Intn(len(testslice)-errors[e])) } errors = append(errors, len(testslice)) for i := 0; i < len(errors)-1; i++ { if i != 0 { teststr = teststr + " " } teststr = teststr + testslice[errors[i]:errors[i+1]] } for i := 0; i < eq; i++ { teststr += "=" } for parts := 0; parts < 5; parts++ { stops := []int{0} for e := 0; e < parts; e++ { stops = append(stops, stops[e]+rand.Intn(len(teststr)-stops[e])) } stops = append(stops, len(teststr)) decoded := "" carry := 0 for i := 0; i < len(stops)-1; i++ { decoded += string(util.Base64DecodeString(teststr[stops[i]:stops[i+1]], &carry)) } if decoded != string(testbuf) { error_list += fmt.Sprintf("(util.Base64DecodeString() failed for length=%v eq=%v err=%v parts=%v)\n", length, eq, err, parts) } buffy := []byte(string(teststr)) decbuffy := util.Base64DecodeInPlace(buffy) if &(decbuffy[0]) != &(buffy[0]) || // verify the in-place property string(decbuffy) != string(testbuf) { error_list += fmt.Sprintf("(util.Base64DecodeInPlace() failed for length=%v eq=%v err=%v parts=%v)\n", length, eq, err, parts) } } } } } check(error_list, "") buffy := make([]byte, 1024) st := "Nehmt, esst. Dies ist mein Leib - sprach der Schokohase" copy(buffy[32:], st) result := util.Base64EncodeInPlace(buffy[:32+len(st)], 32) check(&(buffy[0]) == &(result[0]), true) check(cap(result), cap(buffy)) check(string(result), "TmVobXQsIGVzc3QuIERpZXMgaXN0IG1laW4gTGVpYiAtIHNwcmFjaCBkZXIgU2Nob2tvaGFzZQ==") st = "Nehmt, esst. Dies ist mein Leib - sprach der Schokohase\n" copy(buffy[256:], st) result = util.Base64EncodeInPlace(buffy[:256+len(st)], 256) check(&(buffy[0]) == &(result[0]), true) check(cap(result), cap(buffy)) check(string(result), "TmVobXQsIGVzc3QuIERpZXMgaXN0IG1laW4gTGVpYiAtIHNwcmFjaCBkZXIgU2Nob2tvaGFzZQo=") for n := 0; n <= 12; n++ { buffy = make([]byte, n) for i := range buffy { buffy[i] = byte(i) } check(string(util.Base64EncodeString(string(buffy))), base64.StdEncoding.EncodeToString(buffy)) } }