//We usually generate PDF files for testing with 'cat file.txt | enscript -B -o - | ps2pdf - legitimate.pdf' //file.txt contents are /* Invoice ID: 1337 IBAN: GB29NWBK60161331926825 Service: Money Transfer */ func processFile(w http.ResponseWriter, r *http.Request) { var buf bytes.Buffer r.ParseMultipartForm(10 << 20) file, handler, err := r.FormFile("FileToSign") if err != nil { fmt.Println("Error Retrieving the File") fmt.Println(err) return } fileContents, err := ioutil.ReadAll(file) defer file.Close() fmt.Printf("Uploaded File: %+v\n", handler.Filename) fmt.Printf("File Size: %+v\n", handler.Size) fmt.Printf("MIME Header: %+v\n", handler.Header) todo := r.FormValue("action") if todo == "sign" { filename := filepath.Base(handler.Filename) + ".content.check" // write the whole body at once err = ioutil.WriteFile(filename, fileContents, 0644) if err != nil { panic(err) return } BAcheck, err := checkBankAccount(filename, false) e := os.Remove(filename) if e != nil { log.Fatal(e) } if err != nil { fmt.Fprintf(w, "Not a valid PDF file\n") } if BAcheck == "verified" { hash := md5.New() byteReader := bytes.NewReader(fileContents) if _, err := io.Copy(hash, byteReader); err != nil { log.Fatal("Unable to get hash") } hashInBytes := hash.Sum(nil)[:16] signedMessage, err := SignatureRSA(hashInBytes) if err != nil { log.Fatalln(err) return } if _, err := buf.Write(fileContents); err != nil { log.Fatal(err) return } if _, err := buf.Write(signedMessage); err != nil { log.Fatal(err) return } filename = filepath.Base(handler.Filename) + ".signed" w.Header().Set("Content-Disposition", "attachment; filename=" + filename) w.Header().Set("Content-Type", r.Header.Get("Content-Type")) bReaderDown := bytes.NewReader(buf.Bytes()) io.Copy(w, bReaderDown) } else { fmt.Fprintf(w, "Bank account check failed\n") } } else if todo == "validate" { if len(string(fileContents)) > 256 { byteReader := bytes.NewReader(fileContents) buf := make([]byte, 256) start := byteReader.Len() - 256 n, _ := byteReader.ReadAt(buf, int64(start)) signatureBytes := buf[:n] byteReader2 := bytes.NewReader(fileContents) buf2 := make([]byte, byteReader2.Len() - 256) n2, _ := byteReader2.ReadAt(buf2, 0) contentBytes := buf2[:n2] byteReader3 := bytes.NewReader(contentBytes) hash := md5.New() if _, err := io.Copy(hash, byteReader3); err != nil { log.Fatal("Unable to get hash") } hashInBytes := hash.Sum(nil)[:16] if VerifyRSA(hashInBytes, signatureBytes) { filename := filepath.Base(handler.Filename) + ".content.verify" err = ioutil.WriteFile(filename, contentBytes, 0644) if err != nil { panic(err) return } BAcheck, err := checkBankAccount(filename, true) e := os.Remove(filename) if e != nil { log.Fatal(e) } if err != nil { fmt.Fprintf(w, "Not a valid PDF file\n") } if BAcheck == "verified" { fmt.Fprintf(w, "Money transfer made to the respective bank account.") } else if BAcheck == "getflag" { flag, _ := ioutil.ReadFile("flag") if err == nil { fmt.Fprintf(w, "Money transfer made to the respective bank account. FLAG: " + string(flag)) } else { fmt.Fprintf(w, "Flag file not present") } } else { fmt.Fprintf(w, "Bank account check failed\n") } } else { fmt.Fprintf(w, "Money transfer denied, invalid signature\n") } } else { fmt.Fprintf(w, "File too small to have a signature\n") } } else { fmt.Fprintf(w, "You need to provide action sign or validate\n") } } func checkBankAccount(path string, issigned bool) (string, error) { f, r, err := pdf.Open(path) defer func() { _ = f.Close() }() if err != nil { return "", err } totalPage := r.NumPage() for pageIndex := 1; pageIndex <= totalPage; pageIndex++ { p := r.Page(pageIndex) if p.V.IsNull() { continue } rows, _ := p.GetTextByRow() for _, row := range rows { i := 0 for _, word := range row.Content { if i == 2 { if issigned == false { r, _ := regexp.Compile(`^GB\d{2}\s?([0-9a-zA-Z]{4}\s?){4}[0-9a-zA-Z]{2}$`) match := r.FindString(word.S) //Whitelist bank account number, so we don't accidentally transfer to wrong people if match == "GB29NWBK60161331926825" { return "verified", nil } } else if issigned == true { r, _ := regexp.Compile(`(^broken$|^GB\d{2}\s?([0-9a-zA-Z]{4}\s?){4}[0-9a-zA-Z]{2}$)`) match := r.FindString(word.S) //Check if those incident responders managed to find the flaw in our code if match == "broken" { return "getflag", nil } else if match == "GB29NWBK60161331926825" { return "verified", nil } } } i = i + 1 } } } return "", nil }