package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"flag"
"fmt"
"golang.org/x/crypto/pbkdf2"
"net/url"
"os"
"reflect"
"strconv"
"strings"
)
func main() {
var uri = flag.String("uri", "", "Example: igmobileotp://?action=secactivate&enc=VRUq6IoLWQRCMRITZEHtHUSWJiPwgu%2FN1BFyUHE5kxuHIEYoE3zmNTrAHeeUM5S3gzCnTy%2F%2Bdnbu%2FsjjQW%2BNEISx8C4ra8rLpxOl8E8w4KXHgjeBRgdvSzl%2BbzX5RYRrQlWgK8hsBT4pQYE0eFgW2TmRbzXu1Mu7XjKDcwsJLew32jQC2qyPLP8hljnv2rHwwsMfhQwgJUJYfctwLWWEDUFukEckaZ4O&v=1&mac=mhVL8BWKaishMa5%2B")
var threadsPtr = flag.Int("threads", 4, "Number of threads to use. Set to ncores, or ncores - 1. Load is 100% CPU")
flag.Parse()
threads := *threadsPtr
if *uri == "" {
panic("Specify a URI")
}
obj, err := url.Parse(*uri)
if err != nil {
panic(err)
}
if obj.Scheme != "igmobileotp" {
fmt.Println("Only the scheme igmobileotp is currently supported")
}
// Parse the query string component
q := obj.Query()
if (len(q["action"]) != 1) || (q["action"][0] != "secactivate") {
fmt.Println("Only the secactivate action is currently supported")
}
// Validate the encrypted data really exists
if len(q["enc"]) != 1 {
panic("No enc provided")
}
// Validate we have a MAC that we can verify decryption with
if len(q["mac"]) != 1 {
panic("No mac provided")
}
mac, err := base64.StdEncoding.DecodeString(q["mac"][0])
if err != nil {
panic(err)
}
// Decode the enc paramater
enc, err := base64.StdEncoding.DecodeString(q["enc"][0])
if err != nil {
panic(err)
}
// Extract out the payload that is used for HMAC validation
from := strings.Index(*uri, "?") + 1 // 1 more, because the ?
to := strings.LastIndex(*uri, "&")
hmacPayload := (*uri)[from:to]
fmt.Println(hmacPayload)
// Farm the work out to threads
passwords := make(chan []byte)
doner := make(chan bool, threads)
for i := 0; i < threads; i++ {
go checkPassword(enc[0:8], []byte(hmacPayload), mac, passwords, doner)
}
//for i := 54998317; i < 54998318; i++ {
for i := 0; i < 99999999; i++ {
passwords <- []byte(strconv.Itoa(i))
}
close(passwords)
for i := 0; i < threads; i++ {
<-doner
}
fmt.Println("Password was not found. Is your URI corrupted?")
os.Exit(1)
}
func checkPassword(salt []byte, macedPayload []byte, macValue []byte, passwords <-chan []byte, doner chan<- bool) {
for password := range passwords {
dk := pbkdf2.Key(password, salt, 1000, 64, sha256.New)
// Validate whether the key is correct with a HMAC verification
hmacKey := dk[16:48]
macer := hmac.New(sha256.New, hmacKey)
macer.Write(macedPayload)
calculatedMac := macer.Sum(nil)
if reflect.DeepEqual(calculatedMac[0:12], macValue) {
// Success!
fmt.Println("Password found: ", string(password))
os.Exit(0)
}
}
doner <- true
}