Skip to content

Instantly share code, notes, and snippets.

@azumakuniyuki
Created May 5, 2022 13:54
Show Gist options
  • Save azumakuniyuki/f0590b7eab4a182d5764c863622176a0 to your computer and use it in GitHub Desktop.
Save azumakuniyuki/f0590b7eab4a182d5764c863622176a0 to your computer and use it in GitHub Desktop.
Make a string for SMTP "AUTH PLAIN" from an username and a password
// _ _ _ _
// ___ _ __ ___ | |_ _ __ __ _ _ _| |_| |__ _ __ __ _ ___ _____ _____ _ __ __| |
// / __| '_ ` _ \| __| '_ \ / _` | | | | __| '_ \ _____| '_ \ / _` / __/ __\ \ /\ / / _ \| '__/ _` |
// \__ \ | | | | | |_| |_) | (_| | |_| | |_| | | |_____| |_) | (_| \__ \__ \\ V V / (_) | | | (_| |
// |___/_| |_| |_|\__| .__/ \__,_|\__,_|\__|_| |_| | .__/ \__,_|___/___/ \_/\_/ \___/|_| \__,_|
// |_| |_|
package main
// Usage:
// $ go run ./smtpauth-password username@example.jp password-string-for-smtp-authentication
// $ go run ./smtpauth-password --aws ap-northeast-1 --smtp-password AccessKeyID AccessSecret
import "os"
import "flag"
import "fmt"
import "crypto/hmac"
import "crypto/sha256"
import b64 "encoding/base64"
var Version = "0.0.1"
var Default = map[string]string{
"region": "us-east-1",
}
var Setting = map[string]string{
"region": "",
}
var Options = map[string]uint8{
"exec": (1 << 0),
"test": (1 << 1),
"neko": (1 << 2),
"aws": (1 << 3),
"smtp-password": (1 << 4),
}
func e(mesg string, cont bool) {
if len(mesg) > 0 {
fmt.Fprintf(os.Stderr, " * error0: %s\n", mesg)
if !cont {
os.Exit(1)
}
}
}
func main() {
o := parseoptions()
a := flag.Args()
if o&Options["exec"] > 0 {
username := a[0]
password := a[1]
authtext := ""
if o&Options["aws"] > 0 {
// --aws option specified
if len(username) == 0 {
e("Access Key ID is empty", false)
}
if len(password) == 0 {
e("Secret Access Key is empty", false)
}
parameters := map[string]string{
"date": "11111111",
"service": "ses",
"message": "SendRawEmail",
"terminal": "aws4_request",
"version": "\x04",
}
regionlist := []string{
"us-east-2", // US East (Ohio)
"us-east-1", // US East (N. Virginia)
"us-west-2", // US West (Oregon)
"ap-south-1", // # Asia Pacific (Mumbai)
"ap-northeast-2", // Asia Pacific (Seoul)
"ap-southeast-1", // Asia Pacific (Singapore)
"ap-southeast-2", // Asia Pacific (Sydney)
"ap-northeast-1", // Asia Pacific (Tokyo)
"ca-central-1", // Canada (Central)
"eu-central-1", // Europe (Frankfurt)
"eu-west-1", // Europe (Ireland)
"eu-west-2", // Europe (London)
"sa-east-1", // South America (Sao Paulo)
"us-gov-west-1", // AWS GovCloud (US)
}
regionok := false
for _, e := range regionlist {
// The regsion specified with --region option does not have an SMTP endpoint
if Setting["region"] == e {
regionok = true
break
}
}
if !regionok {
e(fmt.Sprintf("The %s region does not have an SMTP endpoint", Setting["region"]), false)
}
digesthash := ""
smtppasswd := ""
makedigest := func(key, msg string) string {
if len(key) == 0 {
return ""
}
if len(msg) == 0 {
return ""
}
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(msg))
return string(mac.Sum(nil))
}
digesthash = makedigest("AWS4"+password, parameters["date"])
digesthash = makedigest(digesthash, Setting["region"])
digesthash = makedigest(digesthash, parameters["service"])
digesthash = makedigest(digesthash, parameters["terminal"])
digesthash = makedigest(digesthash, parameters["message"])
smtppasswd = b64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s%s", parameters["version"], digesthash)))
if o&Options["smtp-password"] > 0 {
// Print an SMTP password and exit when --smtp-password option was specified
fmt.Printf("%s\n", smtppasswd)
} else {
// Print an authentication text for "AUTH PLAIN" SMTP command
authtext = fmt.Sprintf("%s\x00%s\x00%s", username, username, smtppasswd)
fmt.Printf("%s\n", b64.StdEncoding.EncodeToString([]byte(authtext)))
}
} else {
// Make an credentials for general SMTP Authentication
if len(username) == 0 {
e("Username is empty", false)
}
if len(password) == 0 {
e("Passowrd is empty", false)
}
authtext = fmt.Sprintf("%s\x00%s\x00%s", username, username, password)
fmt.Printf("%s\n", b64.StdEncoding.EncodeToString([]byte(authtext)))
}
}
}
func parseoptions() uint8 {
// Parse arguments given from a command line
var o uint8 = 0
var f_is_amazonses = flag.String("aws", "", "Make SMTP Credentials for Amazon SES")
var f_smtppassword = flag.Bool("smtp-password", false, "Output SMTP Password for Amazon SES")
flag.Parse()
o |= Options["exec"]
if len(*f_is_amazonses) > 0 {
// --aws option specified
o |= Options["aws"]
Setting["region"] = *f_is_amazonses
}
if *f_smtppassword {
// --smtp-password option specified
o |= Options["smtp-password"]
}
return o
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment