Click or drag to resize

Quick Start Guide

This quick start guide covers the basic steps to use the ursa library in a .NET project.

Requirements

Use ursa to generate a tokencode from a RSA SecurID soft token stored in a file.

  1. In your .NET project, install the SamoyedSoftware.ursa NuGet package, or add a reference to a manually downloaded copy of SamoyedSoftware.ursa.dll.

  2. In your code file, add a using statement for the ursa namespace:

    C#
    using SamoyedSoftware.ursa;
  3. Use SecurIdTokenLoad(String) to load the token from the file.

    C#
    string strMyTokenFile = "mytokenfile.txt";
    SecurIdToken token = SecurIdToken.Load(filename);
  4. Use the SecurIdTokenDecrypt(String, String) to decrypt the token. You'll need to supply the password for the token, and for some tokens a Device ID / Serial number.

    C#
    string strMyPassword = "this is my token password";
    string strMyDeviceId = "";
    token.Decrypt(strMyPassword, strMyDeviceId);
  5. Use SecurIdTokenComputeTokencode(DateTime), or if you token requires a PIN use SecurIdTokenComputeTokencode(DateTime, String), retrieve the current tokencode.

    C#
    string strTokenCode = token.ComputeTokencode(DateTime.Now);
    
    // If your token requires a PIN use the following instead
    //string strPIN = "1234";
    //string strTokenCode token.ComputeTokencode(DateTime.Now, strPIN);
Example

The following example is a command-line program that generates a tokencode from a token in stored in a file or from a token string passed as an command-line argument. The complete source for this program is included in the ursa project source code, available from the ursa project homepage.

C#
/*
 * This file is part of ursa, a tokencode generator compatible with 
 * RSA SecurID® 128-bit (AES) tokens. RSA SecurID® is a registered 
 * trademark held by RSA Security LLC.  Neither the ursa project 
 * nor Samoyed Software, LLC are affiliated with or endorsed by 
 * RSA® (RSA Security LLC). 
 * 
 * Copyright 2017 Samoyed Software, LLC <http://www.samoyedsoftware.com>
 *
 * Portions of ursa are based on 
 * stoken 0.92, Copyright 2012 Kevin Cernekee <http://stoken.sf.net/>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using SamoyedSoftware.ursa;

namespace ursaCmd
{
    class Program
    {
        static int Main(string[] args)
        {
            string filename = "";
            string tokenString = "";
            string password = "";
            string deviceid = "";
            string pin = "";
            DateTime time = DateTime.MinValue;
            bool bLoop = false;
            bool bPrintTime = false;
            bool bPrintInfo = false;
            bool bExport = false;
            char exportVersion = (char) 0;


            if (args.Length > 0)
            {
                string strOpt = "";
                string strOptName = "";
                string strNextOpt = "";
                bool bHasNextOpt = false;
                for (int i = 0; i < args.Length; i++)
                {
                    if (args[i].StartsWith("-") || args[i].StartsWith("/"))
                    {
                        strOpt = args[i];
                        if (strOpt.Length < 2)
                            return UsageBadOption(strOpt);
                        strOptName = strOpt.Substring(1);
                        strNextOpt = (i + 1 < args.Length) ? args[i + 1] : "";
                        bHasNextOpt = strNextOpt.Length > 0;

                        switch (strOptName)
                        {
                            case "token":
                                if (!bHasNextOpt)
                                    return UsageMissingOptionValue(strOpt);
                                tokenString = strNextOpt;
                                i++;
                                break;

                            case "pass":
                                if (!bHasNextOpt)
                                    return UsageMissingOptionValue(strOpt);
                                password = strNextOpt;
                                i++;
                                break;

                            case "devid":
                                if (!bHasNextOpt)
                                    return UsageMissingOptionValue(strOpt);
                                deviceid = strNextOpt;
                                i++;
                                break;

                            case "pin":
                                if (!bHasNextOpt)
                                    return UsageMissingOptionValue(strOpt);
                                pin = strNextOpt;
                                i++;
                                break;

                            case "time":
                                if (!bHasNextOpt)
                                    return UsageMissingOptionValue(strOpt);
                                if (!DateTime.TryParse(strNextOpt, out time))
                                    return UsageBadOptionValue(strOpt, args[i + 1], "valid date/time value");
                                i++;
                                break;

                            case "showtime":
                                bPrintTime = true;
                                break;

                            case "loop":
                                bLoop = true;
                                break;

                            case "info":
                                bPrintInfo = true;
                                break;

                            case "export":
                                if (bHasNextOpt && strNextOpt[0] != '-')
                                {
                                    exportVersion = Char.ToLower(strNextOpt[0]);
                                    if (exportVersion != '2' && exportVersion != '3' && exportVersion != 's')
                                        return UsageBadOptionValue(strOpt, args[i + 1], "valid version number (2, 3, or s)");
                                }
                                else
                                    exportVersion = (char) 0;
                                bExport = true;
                                break;

                            default:
                                return UsageBadOption(strOpt);
                        }
                    }
                    else if (i == 0)
                    {
                        filename = args[i];
                    }

                }
            }

            if (bLoop && (time > DateTime.MinValue || bExport))
                return Usage("Option -loop may not be combined with options -time or -export.");

            if (bPrintInfo && bExport)
                return Usage("Option -info may not be combined with option -export.");

            if (filename.Length == 0 && tokenString.Length == 0)
                return Usage("Must specify token file path or use -token to specify token string.");

            try
            {
                SecurIdToken token = null;
                if (tokenString.Length > 0)
                    token = SecurIdToken.Parse(tokenString);
                else if (filename.Length > 0)
                    token = SecurIdToken.Load(filename);

                if (token == null)
                    throw new ApplicationException("Could not parse token.");

                token.Decrypt(password, deviceid);

                if (bExport)
                {
                    string strExport = "";
                    switch (exportVersion)
                    {
                        case '2':
                            SecurIdV2Token t2 = token.AsV2Token;
                            strExport = t2.Export(password, deviceid);
                            break;

                        case '3':
                            SecurIdV3Token t3 = token.AsV3Token;
                            strExport = t3.Export(password, deviceid);
                            break;

                        case 's':
                            SecurIdSdtidToken ts = token.AsSdtidToken;
                            strExport = ts.Export(password, deviceid);
                            break;
                    }
                    Console.WriteLine(strExport);
                }
                else
                {
                    if (bPrintInfo)
                        Console.Write(token.ToString());

                    do
                    {
                        DateTime dt = (time > DateTime.MinValue) ? time : DateTime.Now;

                        string tokenCode = token.ComputeTokencode(dt, pin);

                        if (bPrintTime)
                            Console.Write("{0}\t", dt);
                        Console.WriteLine(tokenCode);

                        if (bLoop)
                            Thread.Sleep((60 - dt.Second + 1) * 1000);
                    } while (bLoop);
                }
            }
            catch (Exception ex)
            {
                return HandleError(ex);
            }

            return 0;
        }

        #region Console Output 

        static int Usage()
        {
            return Usage("", null);
        }

        static int Usage(string err)
        {
            return Usage(err, null);
        }

        static int UsageBadOption(string option)
        {
            return Usage("Option \"{0}\" is not valid.", option);
        }

        static int UsageMissingOptionValue(string option)
        {
            return Usage("Value for option {0} was not specified.", option);
        }

        static int UsageBadOptionValue(string option, string optionValue, string expecting)
        {
            return Usage("Value \"{0}\" for option {1} is not valid.{2}", optionValue, option, expecting.Length > 0 ? " Expecting " + expecting + "." : "");
        }

        static int Usage(string err, params object[] args)
        {
            Console.WriteLine();
            if (err.Trim().Length > 0)
            {

                Console.ForegroundColor = GetErrorColor();

                if (args != null)
                    Console.WriteLine(err, args);
                else
                    Console.WriteLine(err);

                Console.ResetColor();

                Console.WriteLine();
            }
            Console.WriteLine("Usage: {0} {{ TokenFilePath | -token TokenString }} [ <options> ]", System.Diagnostics.Process.GetCurrentProcess().ProcessName.ToLower());
            Console.WriteLine();
            Console.WriteLine("Options:");
            Console.WriteLine("\t-pass Password");
            Console.WriteLine("\t-devid DeviceID");
            Console.WriteLine("\t-pin PIN");
            Console.WriteLine("\t-time DateTime");
            Console.WriteLine("\t-showtime");
            Console.WriteLine("\t-loop");
            Console.WriteLine("\t-export [VersionCode]");
            Console.WriteLine("\t-info");
            Console.WriteLine();
            return 1;
        }

        static void Print(string message, params object[] args)
        {
            Console.Write(message, args);
        }

        static void Print(string message)
        {
            Console.Write(message);
        }

        static void PrintLine(string message)
        {
            Console.WriteLine(message);
        }

        static void PrintLine(string message, params object[] args)
        {
            Console.WriteLine(message, args);
        }

        static int HandleError(Exception ex)
        {
            Console.ForegroundColor = GetErrorColor();
            Console.WriteLine();
            if (ex is ursaException)
                Console.WriteLine("Error: {0}", ((ursaException)ex).ErrorCodeAsString);
            else
            {
                Console.WriteLine("Error: {0}", ex.Message);
                Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
            }
            Console.ResetColor();
            return 2;
        }

        static int HandleError(string message)
        {
            Console.ForegroundColor = GetErrorColor();
            Console.WriteLine();
            Console.WriteLine("Error: {0}", message);
            Console.ResetColor();
            return 2;
        }

        static ConsoleColor GetErrorColor()
        {
            if (Console.BackgroundColor == ConsoleColor.Red || Console.BackgroundColor == ConsoleColor.Magenta || Console.BackgroundColor == ConsoleColor.DarkRed || Console.BackgroundColor == ConsoleColor.DarkMagenta)
                return ConsoleColor.Yellow;

            return ConsoleColor.Red;
        }
        #endregion

    }
}