Why do I need this?
To access my VPN i need to use code from RSA Secure ID token. Sometime VPN disconnects and i need to enter token again and again. It is annoying. Also i am afraid that once i will lost my token and it will take a lot of time to restore it.
So i decided to automate the process. There is no USB port on this token type, so only way to read digits is to “scan” LCD. I decided to do this with my old Logitech Webcam C200. This article shows how to do this. To backlight token i used IKEA lamp.
I used “cheese” tool to setup camera and token. Make sure that token is highlighted, numbers are big and readable.
Getting image from camera
There are number of ways to create screen-shots from the camera. I found that tools which using single frame screen-shot (e.g. mplayer or ffmpeg) giving bad and inconsistent results. Most likely reason is that camera need some time to stabilize and also there is a chance that frame will be affected by light blinking. I found great tool fswebcam. . It captures images from a V4L1/V4L2 compatible device or file, averages them to reduce noise and producing png or jpeg output. It also allows to save result in the file. Experimentally I have found that 10 frames producing optimal and consistent result. Below is a command line and resulted image:
fswebcam -d /dev/video0 --png 1 -F 10 test.png --- Opening /dev/video0... Trying source module v4l2... /dev/video0 opened. No input was specified, using the first. Adjusting resolution from 384x288 to 352x288. --- Capturing 10 frames... Captured 10 frames in 0.37 seconds. (27 fps) --- Processing captured image... Setting output format to PNG, quality 1 Writing PNG image to 'test.png'.
Converting image to numbers
After some unsuccessful attempts with cuneiform and tesseract I found very good and opensource OCR tool for the LCD displays – ssocr. This tool designed for such tasks, so i decided to try it. First of all you need to find coordinated with LCD on the image. I used GIMP crop tool to do this. On the provided image result is: 182 91 139 38 (position and size). After many experiments i was able to recognize image with command provided below:
./ssocr crop 182 91 139 38 -d -1 test.png -t 19 072084
072084 is our number. -t 19 sets threshold (in percent) to distinguish black from white. Also it is possible to produce debug output. With “-D -P” lines you will see a lot of debugging information, as well as testbiod.png file (provided below) with debug output.
It is also possible to avoid temporary png file by using pipe:
./fswebcam -d /dev/video0 --png 4 -F 10 - 2>/dev/null | ./ssocr crop 182 91 139 38 -d 6 -t 30 - 587021
or with debug:
./fswebcam -d /dev/video0 --png 4 -F 10 - 2>/dev/null | ./ssocr crop 182 91 139 38 -d 6 -t 30 - -P -D ================================================================================ flags & VERBOSE=0 thresh=30.000000 flags & PRINT_INFO=0 flags & ADJUST_GRAY=0 flags & ABSOLUTE_THRESHOLD=0 flags & DO_ITERATIVE_THRESHOLD=0 need_pixels = 1 ignore_pixels = 0 number_of_digits = 6 foreground = 0 (black) background = 255 (white) luminance = Rec709 height/width threshold = 2 optind=7 argc=13 ================================================================================ argv[argc-1]=- used as image file name using /tmp for temporary files pattern for temporary file is /tmp/ssocr.img.XXXXXX image width: 352 image height: 288 0.00 <= lum <= 255.00 (lum should be in [0,255]) adjusting threshold to image: 30.000000 -> 30.000000 using threshold 30.00 cropped image width: 139 cropped image height: 38 6.00 <= lum <= 100.00 in cropped image (lum should be in [0,255]) adjusting threshold to image: 30.000000 -> 13.411765 using threshold 13.41 found 6 digits digit 0: (1,2) -> (19,37), width: 18 (13.33%) height/width (int): 1 digit 1: (22,2) -> (41,37), width: 19 (14.07%) height/width (int): 1 digit 2: (44,2) -> (62,37), width: 18 (13.33%) height/width (int): 1 digit 3: (77,2) -> (94,37), width: 17 (12.59%) height/width (int): 2 digit 4: (97,2) -> (115,37), width: 18 (13.33%) height/width (int): 1 digit 5: (121,1) -> (136,37), width: 15 (11.11%) height/width (int): 2 digits are at most 19 pixels wide and 36 pixels high Display as seen by ssocr: _ _ _ _ _ _ |_| |_| | | |_ _| _| _| |_| |_| _| |_ _| 980523
From prototype to solution
As you can see it is possible and relatively easy to get numbers from LCD. Now i did just “proof of concept”. I want to find some box (e.g. one from cookies) to put web camera, token and some USB light inside. Then i am planning to connect it to the Synology DSM box i own and compile everything i need for the PPC target. After this it will be possible to do someting like:
ssh disktation.lan gettoken.sh 123456
Also it will allow me to use result directly in JVPN instead of typing it manually.