package rsa

/*
RSA: RSA encryption, decryption and signing
*/

import (
    "os"
    "fmt"
    "bufio"
    "config"
    "tools/common"
    "tools/rsa/keys"
    "tools/rsa/data"
    "tools/rsa/integer"
)

type RSA struct {
    *keys.Keys
    *data.Blob
    recv *os.File
}

func New() *RSA {
    r := new(RSA)
    r.Keys = keys.New(config.RSA_BASE_INIT, config.RSA_BASE, config.RSA_SIZE)
    r.Blob = data.New()
    return r
}

func (r *RSA) ReadRecvFile() (string, bool) {
    str := ""
    if f, err := os.Open(config.RSA_RECV_FILE); !common.IsError(err, fmt.Sprintf("%s", config.RSA_RECV_FILE)) {
        defer f.Close()
        scanner := bufio.NewScanner(f)
        for scanner.Scan() {
            str += scanner.Text()
        }
        return str, true
    }
    return str, false
}

func (r *RSA) Encrypt(msg string, n, e *integer.RSAInt) []*integer.RSAInt {
    l := r.Set(data.TXT, data.Data(msg)).AsNumbers().ToList()
    for i := 0; i < len(l); i++ {
        l[i].PowMod(e, n)
    }
    return l
}

func (r *RSA) Sign(msg string) []*integer.RSAInt {
    l := r.Set(data.TXT, data.Data(msg)).AsNumbers().ToList()
    for i := 0; i < len(l); i++ {
        l[i].PowMod(r.Private().D(), r.Public().N).String()
    }
    return l
}

func (r *RSA) EncryptNSign(msg string, n, e *integer.RSAInt) []*integer.RSAInt {
    l := r.Set(data.TXT, data.Data(msg)).AsNumbers().ToList()
    if r.Public().N.Gt(n) {
        for i := 0; i < len(l); i++ {
            l[i].PowMod(e, n).PowMod(r.Private().D(), r.Public().N)
        }
    } else {
        for i := 0; i < len(l); i++ {
            l[i].PowMod(r.Private().D(), r.Public().N).PowMod(e, n)
        }
    }
    return l
}

func (r *RSA) Decrypt(l []*integer.RSAInt) string {
    for i := 0; i < len(l); i++ {
        l[i].PowMod(r.Keys.Private().D(), r.Keys.Public().N)
    }
    r.FromList(l)
    return string(r.AsText().Repr())
}

func (r *RSA) Unsign(l []*integer.RSAInt, n, e *integer.RSAInt) string {
    for i := 0; i < len(l); i++ {
        l[i].PowMod(e, n)
    }
    r.FromList(l)
    return string(r.AsText().Repr())
}

func (r *RSA) DecryptNUnsign(l []*integer.RSAInt, n, e *integer.RSAInt) string {
    if n.Gt(r.Public().N) {
        for i := 0; i < len(l); i++ {
            l[i].PowMod(e, n).PowMod(r.Private().D(), r.Public().N)
        }
    } else {
        for i := 0; i < len(l); i++ {
            l[i].PowMod(r.Private().D(), r.Public().N).PowMod(e, n)
        }
    }
    r.FromList(l)
    return string(r.AsText().Repr())
}
