diff --git a/.gitignore b/.gitignore
index 66fd13c..285d217 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
+apg
# Test binary, built with `go test -c`
*.test
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/apg.go.iml b/.idea/apg.go.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/apg.go.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..09dbac8
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..6385bbc
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 900337c..655265a 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,30 @@
# apg.go
-Advanced Password Generator Clone
+_apg.pl_ is a simple APG-like password generator script written in Go. It tries to replicate the functionality of the "[Automated Password Generator](https://web.archive.org/web/20130313042424/http://www.adel.nursat.kz:80/apg)", which hasn't been maintained since 2003. Since more and more Unix distributions are abondoning the tool, I was looking for an alternative. FreeBSD for example recommends "security/makepasswd", which is also written in Perl but requires much more dependency packages and doesn't offer the feature-set/flexibility of APG. Therefore I decided to write my own implementation. As I never used the "pronouncable password" functionality, I left this out in my version.
+
+## Usage
+Simply add the execute-flag to the script and run it
+```sh
+$ chmod +x apg
+$ ./apg
+```
+
+## Systemwide installation
+To be a proper APG replacement, i suggest to install it into a directory in your PATH and symlink it to "apg":
+```sh
+$ sudo cp apg /usr/local/bin/apg
+```
+
+## CLI options
+_apg.go_ replicates some of the parameters of the original APG. Some parameters are different though:
+
+- ```-m, --minpasslen ```: The minimum length of the password to be generated
+- ```-x, --maxpasslen ```: The maximum length of the password to be generated
+- ```-n, --numofpass ```: The amount of passwords to be generated
+- ```-E, --exclude ```: Do not use the specified characters in generated passwords
+- ```-U, --uppercase```: Use uppercase characters in passwords
+- ```-N, --numbers```: Use numeric characters in passwords
+- ```-S, --special```: Use special characters in passwords
+- ```-H, --human```: Avoid ambiguous characters in passwords (i. e.: 1, l, I, o, O, 0)
+- ```-c, --complex```: Generate complex passwords (implies -U -N -S and disables -H)
+- ```-h, --help```: Show a CLI help text
+- ```-v, --version```: Show the version number
\ No newline at end of file
diff --git a/apg.go b/apg.go
new file mode 100644
index 0000000..fdc7965
--- /dev/null
+++ b/apg.go
@@ -0,0 +1,136 @@
+package main
+
+import (
+ "crypto/rand"
+ "flag"
+ "fmt"
+ "log"
+ "math/big"
+ "os"
+)
+
+// Constants
+const DefaultPwLenght int = 20
+const VersionString string = "0.1.0"
+const PwLowerCharsHuman string = "abcdefghjkmnpqrstuvwxyz"
+const PwUpperCharsHuman string = "ABCDEFGHJKMNPQRSTUVWXYZ"
+const PwLowerChars string = "abcdefghijklmnopqrstuvwxyz"
+const PwUpperChars string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+const PwSpecialCharsHuman string = "\"#/\\$%&+-*"
+const PwSpecialChars string = "\"#/!\\$%&+-*.,?=()[]{}:;~^|"
+const PwNumbersHuman string = "23456789"
+const PwNumbers string = "1234567890"
+
+type cliOpts struct {
+ minPassLen int
+ maxPassLen int
+ numOfPass int
+ useComplex bool
+ useLowerCase bool
+ useUpperCase bool
+ useNumber bool
+ useSpecial bool
+ humanReadable bool
+ excludeChars string
+ showHelp bool
+ showVersion bool
+}
+
+var config cliOpts
+
+// Read flags
+func init() {
+ // Bool flags
+ flag.BoolVar(&config.useLowerCase, "L", true, "Use lower case characters in passwords")
+ flag.BoolVar(&config.useUpperCase, "U", false, "Use upper case characters in passwords")
+ flag.BoolVar(&config.useNumber, "N", false, "Use numbers in passwords")
+ flag.BoolVar(&config.useSpecial, "S", false, "Use special characters in passwords")
+ flag.BoolVar(&config.useComplex, "C", true, "Generate complex passwords (implies -L -U -N -S, disables -H)")
+ flag.BoolVar(&config.humanReadable, "H", false, "Generate human-readable passwords")
+ flag.BoolVar(&config.showVersion, "v", false, "Show version")
+
+ // Int flags
+ flag.IntVar(&config.minPassLen, "m", 10, "Minimum password length")
+ flag.IntVar(&config.maxPassLen, "x", DefaultPwLenght, "Maxiumum password length")
+ flag.IntVar(&config.numOfPass, "n", 1, "Number of passwords to generate")
+
+ // TODO: Exclude chars are missing, yet
+
+ flag.Parse()
+ if config.showVersion {
+ _, _ = os.Stderr.WriteString("Advanced Password Generator v" + VersionString + "\n")
+ os.Exit(0)
+ }
+}
+
+func main() {
+ pwLength := config.minPassLen
+ if pwLength < config.minPassLen {
+ pwLength = config.minPassLen
+ }
+ if pwLength > config.maxPassLen {
+ pwLength = config.maxPassLen
+ }
+ if config.useComplex {
+ config.useUpperCase = true
+ config.useLowerCase = true
+ config.useSpecial = true
+ config.useNumber = true
+ config.humanReadable = false
+ }
+
+ pwUpperChars := PwUpperChars
+ pwLowerChars := PwLowerChars
+ pwNumbers := PwNumbers
+ pwSpecialChars := PwSpecialChars
+ if config.humanReadable {
+ pwUpperChars = PwUpperCharsHuman
+ pwLowerChars = PwLowerCharsHuman
+ pwNumbers = PwNumbersHuman
+ pwSpecialChars = PwSpecialCharsHuman
+ }
+
+ var charRange string
+ if config.useLowerCase {
+ charRange = charRange + pwLowerChars
+ }
+ if config.useUpperCase {
+ charRange = charRange + pwUpperChars
+ }
+ if config.useNumber {
+ charRange = charRange + pwNumbers
+ }
+ if config.useSpecial {
+ charRange = charRange + pwSpecialChars
+ }
+
+ /*
+ for i := 1; i <= config.numOfPass; i++ {
+ fmt.Println(i)
+ }
+ */
+ pwString := getRandChar(&charRange, pwLength)
+ fmt.Println(pwString)
+
+}
+
+func getRandChar(charRange *string, pwLength int) string {
+ availCharsLength := len(*charRange)
+ charSlice := []byte(*charRange)
+ returnString := []byte{}
+ for i := 0; i < pwLength; i++ {
+ randNum := getRandNum(availCharsLength)
+ returnString = append(returnString, charSlice[randNum])
+ }
+ return string(returnString)
+}
+
+func getRandNum(maxNum int) int {
+ maxNumBigInt := big.NewInt(int64(maxNum))
+ randNum64, err := rand.Int(rand.Reader, maxNumBigInt)
+ if err != nil {
+ log.Fatal("An error occured generating random number: %v", err)
+ }
+ randNum := int(randNum64.Int64())
+ return randNum
+}