5,276,406 members and growing! (16,097 online)
Email Password   helpLost your password?
General Programming » Cryptography & Security » Security     Intermediate License: The BSD License

AxiomaticTokenizer

By GeorgeHara

Financial security with one-time tokens
Javascript, HTML

Posted: 27 Mar 2008
Updated: 2 Jul 2008
Views: 3,614
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
5 votes for this Article.
Popularity: 3.06 Rating: 4.38 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
1 vote, 20.0%
3
1 vote, 20.0%
4
3 votes, 60.0%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Download axiomatictokenizer_attach.zip - 188 KB



Contents

Screenshots

Source code license

Introduction

Background

Who should use it?

Features

Service partners

Sponsored entities

Payment delay

Inheritors

Arbiters

Subscriptions

Group authentication

Show payment history

Typical integration

Custom settings

Adding a service

Architecture

Reference code format

Token format

Encrypted tokens

Execution proof

Weaknesses

Integration tips

RsaKeyGen

Token submit form

The source code

Browser detection

Portability

Color scheming

Wizard-like user interface

Translation

Known issues

Q&A

History



Screenshots

Main screenshot:

axiomatictokenizer.png



"Make payment" / keyboard screenshot:

axiomatictokenizer2.png



Source code license

Developed by the AxiomaticId Entity (www.axiomaticid.org). Released under a "Common Sense License" / "Public Domain License".

Original author: George Gabriel Hara (www.gardenerofthoughts.org).

Original SHA256 code by Angel Marin, Paul Johnston (anmar.eu.org/projects/jssha2), released under a BSD license.

Original BigInteger code by Tom Wu (www-cs-students.stanford.edu/~tjw/jsbn), released under a BSD license.



Introduction

This article presents a mechanism to dramatically increase the security of online financial services, like digital currency services and banks, by separating the user authentication from the Internet and by authenticating every action chosen by the user.

The article also presents certain techniques which improve the quality of JavaScript / HTML applications, like portability, color scheming, translation and wizard-like user interface.

The implementation, AxiomaticTokenizer, is an open source application developed in HTML and JavaScript, specifically designed for mobile devices (like PDAs).

AxiomaticTokenizer works on a variety of web-browsers: Firefox, InternetExplorer, InternetExplorer Mobile, Opera, Opera Mobile, Safari.



Background

The security of online payments is today under heavy attack and things are only getting worse as more and more people start making payments over the Internet. Threats like spyware and phishing destroy user confidence in online services who are expected to "do something".

Consider the classical way of making an online payment: a user creates an account with a service provider, and he authenticates himself into his account with the account name and a password. The problem here is that the computer which sends the password to the service could be infected with spyware, spyware which could intercept and send the password to a thief who could later log in the user's account and steal all the digital currency.

This problem could be solved with a dedicated portable device which can access the Internet, device which would not allow users to install and run other applications. Such a device could not, in theory, contain spyware. But software is buggy and it can never be trusted 100%, particularly not when the amount of code required to make such a device work is huge.

But there is another way, way which is critical for the user who means business, the user who manages a lot of digital currency online. By separating the authentication process from the communication process, maximum security is reached.

The dedicated device no longer needs to be connected to the Internet, it simply has to produce the authentication information which the user can send to the service together with the request to execute a certain action in his name / account.

Currently, there are such devices, like CryptoCard, but their problem is that they generate a token which is not dependent on the payment information and can therefore be used to authenticate whatever information leaves a computer infected with spyware and malware, information which could be different from the one typed by the user into his web-browser (because it can be modified by malware, on-the-fly, like in this case).

For this mechanism to be truly safe, the tokens must depend on the payment information. The process is straight forward. The user types into the device all the information which is necessary to make a payment. Then, the device generates a token, a text which the user can type into a web-browser on a computer which is connected to the Internet. The token is unique every time the user makes a payment, and is created in a deterministic way using cryptographic operations (hashing), so someone who intercepts it can NOT use it (again) to make a different payment, like they can in the case of passwords.

The service verifies that the action requested by the user was indeed initiated by him, by using the payment information from the token sent by the user, to generate a token in the same way. If the two tokens are the same, only the owner of the account could have sent the user token, so the service can confidently execute the requested action.

The one thing which makes it impossible for anyone, other than the user who owns the account and for the service, to generate the correct token is the user's password (which is actually called a shared secret because it's known by the user and by the service).

The shared secret is sent by the user to the service, when the user account is created, also using cryptographic operations (asymmetric encryption), in a way which makes it impossible for anyone to decipher it. After this, the shared secret is never sent to the service, like passwords are, but only used to generate tokens, by both the user and by the service. The way tokens are generated makes it impossible for anyone to extract the shared secret.

The original intent was to develop a complex solution, using full asymmetric cryptography (encryption and signatures), which would cover all technical sides of an online transaction (not necessarily a payment). The problem of such a solution is that it's just too complex for generalized use.

From the need to simplify and generalize the use of secure online payments, AxiomaticTokenizer was born. It is a small application written in HTML and JavaScript, and is therefore highly portable, running on all major web-browsers, on various operating systems, either on desktop computers or on PDAs. AxiomaticTokenizer is an open source solution which can be peer reviewed easily using a simple text editor.

A major win for this simplified solution is that users only need to know their passphrase. A single passphrase is enough for all services and accounts, because the shared secret is not the passphrase itself, but a hash of it, and therefore no service can know the shared secret for any other service or account. Users don't need to store key pairs, signed documents, encrypted documents, documents which need to be backed-up, documents which could be lost (and digital currency along them) or forcefully revealed to thieves.

For users, AxiomaticTokenizer provides a simple, standardized user interface for making secure payments. For service providers, integration with the token standard is simple and can be done with ease. In fact, since AxiomaticTokenizer is released into the public domain, it can be modify in any way to fit the requirements of each service.

Simplicity, standardization of user interface and safety are the key features which make AxiomaticTokenizer the ideal solution for the generalized use of highly secure payments online.



Who should use it?

Password-based security is extremely simple, so why would a user trade this simplicity for token-based security which require some effort to type the tokens?

Users who only have several hundreds dollars worth of digital currency in their accounts, have no reason to do this. However, the necessity to protect large amounts of digital currency, starting from (tens of) thousands of dollars worth of digital currency, motivates users enough to deal with token-based security.



Features

Multi-service support.

Multi-currency support.

Support for service partners.

Support for sponsored entities.

Support for payment delay.

Support for inheritors.

Support for group authentication.

Support for payment arbitration.

Support for subscriptions (/ repeated payments).

The payment history can be hidden from all users.

Actions specific for online payment services.

Asymmetric encryption (RSA) for sending the shared secret (derived from the user's passphrase) to the service.

Customizable token hash field size. This is meant to reduce the amount of characters which users need to type.

Optional spy protection for tokens. The disadvantage of this protection is that it increases significantly the size of the tokens.

Account name checksums meant to ensure that if the user types the wrong account name, he is warned about it. Users should publish their account names together with their checksums, like this "Alice/65".

Private account names. By simply adding "#" at the end of an account name, the account name sent to the service is actually a mix of the written account name and of the service's name, in a way which effectively hides the written account name from the service.

Color themes.

Multi-language support.

Table with mappings between two dice and characters. This is meant to help users to generate truly random passphrases.

Multi-platform: Firefox, InternetExplorer, InternetExplorer Mobile, Opera, Opera Mobile, Safari.

Easy to check HTML and JavaScript open source code.



Payment token example

AT1; MTM; MP; 20080701052542; aliceakula.stash; bobbonkers.pub; NA; AUG; 10; 3E2 485 C96 22D DDF 8;



Service partners

Service partners are entities which bring users to a service, and they receive a fraction of the payment fee charged by the service from these users. Service partners help a service grow faster.

When you create an account with a service, you have the possibility to specify the account name of the service partner which recommended the service to you.

If you do specify the account name of a service partner when you create an account, you will be charged a smaller fee for every payment you make from that account.

Here is an example of how the payment fee could be split. The payment fee is 1% from the amount of paid digital currency. The following percentages are from the fee:

  • The service gets 40%.

  • The developer of the application which generated the token for account creation (or setting change) gets 5%.

  • If the account has a service partner, the partner gets 30%, else the service gets it.

  • If the account has a service partner, the user gets 20% (as a bonus), else the service gets it.

  • If the account has a sponsored entity, the sponsored entity gets 5%, else the service gets it.

Only the entities chosen by the service may be service partners. This is so that the users, in general, could not be service partners for their own accounts.



Sponsored entities

When you create an account with a service, you have the possibility to specify the account name of an entity which you want to sponsor.

Every time you make a payment, the sponsored entity (automatically) receives a fraction of the fee which is charged from you by the service.

If your account has no sponsored entity, the service gets the entire payment fee.

Only the entities chosen by the service may be sponsored entities. This is so that the users, in general, could not be sponsored entities for their own accounts.



Payment delay

If you have an account whose name you make public, in order to enhance its security, all payments made from the account can in fact be made some time after you request the service to make them.

This way, the account acts like a vault with a timed door, door which, for example, can't physically be opened during the night.

For security reasons, once the payment delay is set, it can only be increased (not decreased).



Inheritors

A user account may have inheritors. This is a feature which lets users specify to the service to automatically move all the digital currency from their accounts to the inheritor accounts, in case they become unable to access their own accounts.

Let's consider that Alice, who has an account with the service, dies or becomes permanently incapacitated to access her account. Without inheritor accounts, it would be very difficult for Bob, her husband, and Claudia, her daughter, to receive the inherited digital currency.

But if Bob and Claudia have an account with the same service, Alice can add Bob's and Claudia's accounts as inheritor accounts for her own account. If, during a period of (for example) one year (the actual value is set when an account is created), Alice doesn't send any valid token to the service, her account would enter in inheritance mode, that is, all the digital currency from her account would be automatically moved to the inheritor accounts, Bob's and Claudia's account.

The way the digital currency is split depends on how many inheritance shares Alice allocated for each inheritor.

The number of inheritance shares is specified when Alice adds an inheritor to her account. The digital currency is divided for each inheritor as a fraction equal with the number of inheritance shares allocated for the inheritor divided by the total number of inheritance shares allocated for all inheritors of that account.

For example, if Bob has B inheritance shares, and Claudia has C inheritance shares, Bob receives a fraction equal with "B / (B + C)" from the digital currency in Alice's account, and Claudia receives a fraction equal with "C / (B + C)".



Cascading inheritance

The automatic movement of the inherited digital currency from an account to the inheritor accounts has an interesting side effect: cascading inheritance.

Let's say that Alice has Bob as inheritor, and Bob has Claudia as inheritor. If at some point both Alice and Bob become unable to access their accounts, Claudia will receive the digital currency from both of them, of course when each account enters into inheritance mode.



Arbiters

Whenever you want to make a payment in order to buy something, you can use an arbiter to intermediate the transfer of digital currency.

To do this, simply type the account name of the arbiter in the "Arbiter account name" edit-box from the "Make payment" page, in AxiomaticTokenizer.

When you send the generated token to the service, the digital currency is taken out of your account and put in a queue which contains all arbitrated payments, from all users.

At this point the digital currency is still owned by you, but is under the sole control of the service, and under contract that it will be sent to the account chosen by the arbiter.

The arbiter can decide to either send the digital currency back to you or to send it to the recipient of the payment. The arbiter can not (physically) do anything else with the digital currency, like disappear with it (unless the arbiter and the recipient of your payment are the same entity).

Note that if you use an arbiter, you may be charged an additional payment fee (the maximum fee depends on each service).



Subscriptions

Sometimes you may want to subscribe to a service, or purchase something in installments, and have the periodic payments automatically made.

You can use the "Setup subscription" action to setup a payment which will be made to same account name, for a specified amount of currency, for a number of times.

The first payment is made when you setup the subscription, then repeatedly after the timeframe specified there elapses.



Group authentication

Group authentication can be used by organizations to ensure that access to an account is possible only if a minimum number of members of the organization agree to execute the same action.

For example, an organization might have an account with a payment service where it keeps (some of) its money. The organization would not want any single member to have full access to this account, but rather ensure that all payment requests are executed only if at least 3 (out of 5) members of the organization agree on the payment.

When group authentication is used to execute an action, all members who generate tokens must type the same information in AxiomaticTokenizer (except, of course, their own passphrase). Then, they must send their tokens using a form (provided by the service) similar to the token submit form included in the attached archive.

The service checks if all tokens are valid for that account and ensures that all information from the tokens is the same, except for the time seed and for the token integrity hash. If all this is correct, the action is executed.

Two members of a group can't have the same passphrase or shared secret.

For security reasons, once an account is created, group authentication can't be changed.

This is because the tokens which would form the action to change this setting can be replaced on their way to the service, thusly making it virtually impossible to be certain in advance who would control the account after this setting is changed. It is possible to be sure of this, but the necessary management would be too complex for users.

Although this could also happen when the account is created, the account doesn't contain any digital currency at that point so it can be abandoned unless all group members receive back from the service their execution success proof.

All actions, except "Change passphrase" and "Login account", are affected. The token submission form of a service (which has support for group authentication) must provide a way to show enough edit-boxes where the tokens of the members of the user organization may be typed.

When an account is created, the number of tokens typed in the token submission form must be equal with the total number of members of the group, number specified in the "Create account" token (of each member).

In the case of all other actions (affected by group authentication), the number of tokens must be equal with the required number of present members; otherwise, the action is not executed.



Subtlety

It's very important that an action to be executed is authenticated by the exact required number of present members, not by more.

Consider that an account has group group authentication set to "3 / 9" (3 out of 9).

If a payment is being authenticated and all 9 members generate tokens for the payment request, an attacker who could intercept the token submit form could split the 9 tokens in 3 parts, and then send them to the service as separate payment requests.

Since the tokens don't have a way to identify that they refer to the same unique action, the service can't tell that all 3 parts do in fact refer to the same unique payment and it would execute execute all 3 payments.

The token time seed could be used as a way to identify the same unique action for any number of tokens, however that would require that all group members synchronize it so that the service could mandate that it too be the same for all the tokens of the group sent in the same token submit form.



Show payment history

People will always need a public account where to receive digital currency, but they also need an account which can be hidden from anyone else; "hidden" doesn't mean hidden from the service, but from other people.

The problem is how to transfer currency from the public account to the hidden account, without other people ever knowing of the transfer. This is solved, by the service, by not keeping the history for all the payments into and out of the public account.

In order allow this, AxiomaticTokenizer lets users specify whether to keep or not the history of all the payments for an account. For security reasons, this can be only specified when an account is created, or changed later from "Yes" to "No" (never from "No" to "Yes").

Even if the user chooses to not keep the history of the payments, the service may still keep it internally, but it's guaranteed that no other user will see it.

This feature isn't useful for organizations who need to keep track of the payments they receive and make, but they can use delayed payments and group authentication anyway.

Individuals may find this feature to be the only one to protect them from criminals who would want to see what currency they have in their accounts, how much currency has entered into the accounts and to what accounts was the currency moved.



Typical integration

AxiomaticTokenizer is only the client side, the user interface. An online payment service has to implement the server side, that is, code which parses the incoming tokens and executes the requested actions in the database.

You must implement the following tokens in your system:

  • Create account.

  • Change passphrase.

  • Login account.

  • Make payment.

All other tokens are optional.



The following information is required for a service to be integrated in AxiomaticTokenizer:

  • Service name (display text and internal), like "Metal Money" and "MetalMoney". The internal service name must have at least 5 characters and may never be changed.

  • Service ID, like "MTM" (for "Metal Money"). The service ID should be short because all tokens include it, and the user has to type it.

  • Up to 3 weblinks which have forms where a token may be typed and submitted to the service for processing. There is more than one weblink in order to mitigate DDOS attacks.

  • The newest version for tokens.

  • Accepted service actions. See the available actions below.

  • Does the service have support for service partners? See Service partners for details.

  • Does the service have support for sponsored entities? See Sponsored entities for details.

  • Does the service have support for payment delay? See Payment delay for details.

  • Does the service have support for inheritance? See Inheritors for details.

  • Does the service have support for group authentication? See Group authentication for details.

  • Does the service have support for arbiters? See Arbiters for details.

  • Must tokens always be sent encrypted to the service? (If yes, the tokens can be sent through unencrypted communication channels, but are much longer and difficult to type.)

  • The number of bytes from the token hash field which are included in the token, and compared on the service's side. If this is less than 8, the entire hash is used. This is used only for unencrypted tokens, to reduce their size.

  • Accepted currency names. See the available names below.

  • RSA key identifier, like "MMK1".

  • RSA public key exponent, like 65537.

  • RSA public key modulus; this should have 2048 bits. Must be a hexadecimal string.

Here are the available service actions: Create account, Change passphrase, Change service partner, Change sponsored entity, Change payment delay, Change inheritance trigger timeframe, Change show payment history, Add inheritor, Remove inheritor, Login account, Make payment, Setup subscription.

The "Generate account locator" service action is automatically added for all services.

Here are the available currency names: Gold gram (AUG), Gold ounce (AUO), Silver gram (AGG), Silver ounce (AGO), Australian Dollar (AUD), British Pound (GBP), Canadian Dollar (CAD), Chinese Yuan (CNY), Euro (EUR), Japanese Yen (JPY), New Zealand Dollar (NZD), Swiss Franc (CHF), US Dollar (USD). Other currency names can be added.



Custom settings

You may want to give to your users the possibility to download and use the original AxiomaticTokenizer, but with some customized internal values, like the default language and color scheme.

Since you can't change AxiomaticTokenizer, you can only change its file name. The file name may contain custom settings in the form "name=value", all separated by "_" (including the first one). Some custom settings may be lists, in which case the items of the list are separated by ",".

AxiomaticTokenizer parses the name of the file form where it is started and changes some internal values to match those specified.

Here is the list of possible custom settings:

  • "clr" = the name of the initial color scheme.

  • "kb" = show the screen keyboard. If the value of this settings is "true", the keyboard is displayed, else it is hidden.

  • "lng" = the ID of the initial language.

  • "spart" = the default service partner account name.

  • "vsn" = a list of the internal names of the services which will be visible to the user in the "Service name" combo-box. If this is missing, all service names are visible.

If a custom setting is not specified, the internal default value is used.

Here is an example of a file name which contains custom settings: "axiomatictokenizer _ clr=paleblue _ lng=ro _ vsn=MetalMoney, FiatMoney.htm" (ignore the blank spaces). When AxiomaticTokenizer is started from a file with this name, the initial color scheme is pale-blue, the initial language is Romanian, and the visible service names are only "MetalMoney" and "FiatMoney".



Adding a service

You can easily add a new service to AxiomaticTokenizer.

Open the source code in a text editor and search for the following text: "var ServiceInfos". This variable is an array which contains the information for all supported services.

Copy one of the existing service elements, as a new service element, and change its information, particularly:

  • "ServiceNameItemDisplayText".

  • "ServiceNameItemValue".

  • "ServiceId".

  • "TokenSubmitFormWeblink".

  • "RsaKeyId".

  • "RsaPublicKeyM".



Architecture

One-time tokens are like one-time passwords. They can be used to secure data only one time. After they are used, they must be discarded, else they could be used to perform the same action again.

The difference between one-time tokens and one-time passwords is that a token cryptographically secures the data which has to be sent from the client / user to the server / service (where it's to be used), whereas a password is simply used for comparison.

Basically, a token is generated from the data which has to be sent to the service (like the account name of the user, the account name of the recipient of the payment, the amount of currency to be paid), some dynamic data (like the current time) which makes the token different every time, and a secret, called shared secret, which is known to both the user and the service.

The shared secret is sent only once to the service, when the user creates his account, not every time an action has to be performed (like for passwords).

The token contains the plain data which the service has to know in order to re-create the token on its own, and a hash of this data. If the user token and the service token are the same, it means that the shared secret which was used by the user to generate his token is the same as the shared secret from the user's account. Thusly, the user and his action are authenticated and the payment is executed.

Tokens authenticate every action made by the owner of the account, instead of just the login (as is with passwords).



Data filling

The letter case (for names and passphrases) is insensitive everywhere. During comparisons and hashing, all text is converted to upper case.

All texts are encoded in ASCII-7.

A token is formed by several fields, each two being separated by a token field separator: ";". A token always ends with a token field separator. This separator is not included in any data to hash.

Long texts are always displayed in motes of 3 characters with a mote separator (= a blank space) among them. This separator is not included in any data to hash.



Time seed

A time seed is formed from the following concatenated textual time information, represented in UTC coordinates:

  • Year, 4 digits.

  • Month, 2 digits.

  • Day of month, 2 digits.

  • Hour, 2 digits.

  • Minute, 2 digits.

  • Second, 2 digits.

The time seed of the last successfully executed token must be stored, for each account, by the service in order to know that the future tokens with a time seed smaller or equal with it are not to be executed.

In the case of group authentication, the stored time seed is the biggest one from all the tokens received in the same token submit form.



Shared secret generation

A shared secret is the textual representation (in base 16) of a passphrase blender.

The passphrase blender version "1" applies the SHA256 hash 20 times iteratively (= over the previous binary hash), of the following concatenated information:

  • Passphrase blender seed.

  • Service name (the internal one).

  • User account name.

  • User passphrase.

This algorithm allows the user to use the same passphrase for all services because the shared secret is different for each of them (and no service can retrieve the user's passphrase).



Account locator generation

An account locator is the textual representation (in base 16) of an account name blender.

The account name blender version "1" takes the first 8 bytes of the SHA256 hash of the following concatenated information:

  • Account name blender seed.

  • Service name (the internal one).

  • User account name.

This algorithm allows the user to use the same account name for all services, without the two services being able to link the accounts to the same user, because the account locator is different for each of them.



Execution proofs

The execution proofs are automatically generated, and displayed to the user, for all tokens.

An execution proof version "AT1" is the textual representation (in base 16) of the first 8 bytes of the SHA256 hash of the following concatenated information (of the token):

  • The execution success / error proof seed.

  • The token fields which are hashed to generate the token integrity hash (without the token field separators).

The service must always compute and include an execution proof in the response sent to the user, except when the time seed of the processed token is smaller or equal with the time seed of the last successfully executed token.

The execution success proof must be sent only if the requested action was successfully executed.

The execution error proof must be sent only if an error occurred while executing the requested action. It must not be sent if the token is queued for later execution, or is malformed, or if the time seed of the token is smaller or equal with the time seed of the last successfully executed token.



Reference code format

If you need to quickly locate a token long after it is generated, keep the token reference code, if one is displayed by AxiomaticTokenizer.



Payment reference code

A payment reference code is displayed for all generated "Make payment" tokens. A payment reference code has the same version as the associated token.

A payment reference code version "AT1" is the textual representation (in base 16) of the first 8 bytes of the SHA256 hash of the following concatenated information (of the token):

  • Reference code seed.

  • Token version.

  • Action ID.

  • Time seed.

  • Service name (the internal one).

  • User account name.

  • Recipient account name.

  • Arbiter account name.

  • Currency name.

  • Amount to pay.



Subscription reference code

A subscription reference code is displayed for all generated "Setup subscription" tokens. A subscription reference code has the same version as the associated token.

A subscription reference code version "AT1" is the textual representation (in base 16) of the first 8 bytes of the SHA256 hash of the following concatenated information (of the token):

  • Reference code seed.

  • Token version.

  • Action ID.

  • Time seed.

  • Service name (the internal one).

  • User account name.

  • Recipient account name.

  • Currency name.

  • Amount to pay.

  • Subscription repeat timeframe.

  • Subscription repeat count.



Token format

AxiomaticTokenizer implements tokens specifically to be used for a payment service.

A token is formed by several fields, each two being separated by a token field separator: ";". This is not included in the data to hash.

A token may contain white spaces. These must be removed before the token is processed.



Payment token example

AT1; MTM; MP; 20080701052542; aliceakula.stash; bobbonkers.pub; NA; AUG; 10; 3E2 485 C96 22D DDF 8;



Create account

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CA".

  • Time seed.

  • Generator application identifier.

  • The account name of the user.

  • The account name of the service partner which is associated to the user's account. If the user didn't specify a service partner, this field contains "NSP".

  • The account name of the sponsored entity which is associated to the user's account. If the user didn't specify a sponsored entity, this field contains "NSE".

  • Payment delay. If the user didn't specify a payment delay, this field contains "NPD".

  • Inheritance trigger timeframe.

  • Show payment history. This is "SH" if the history has to be shown, and "HH" if it has to be hidden.

  • Group authentication. This field contains two numbers: the first is the required number of present members, the second is the total number of members of the group.

  • The textual representation of the new shared secret.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated together. Since there is no existing shared secret to guarantee authenticity, this is generated because it ensures that there is no accidental corruption of the token.

This token is always asymmetrically encrypted with the service's public key.



Change passphrase

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CP".

  • Time seed.

  • The account name of the user.

  • The textual representation of the new shared secret. The new shared secret may not be the same as the old one.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the (existing) shared secret at the end.

This token is always asymmetrically encrypted with the service's public key.



Change service partner

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CSP".

  • Time seed.

  • Generator application identifier.

  • The account name of the user.

  • The account name of the service partner which is associated to the user's account. If the user didn't specify a service partner, this field contains "NSP".

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end.

This token may be unencrypted.



Change sponsored entity

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CSE".

  • Time seed.

  • Generator application identifier.

  • The account name of the user.

  • The account name of the sponsored entity which is associated to the user's account. If the user didn't specify a sponsored entity, this field contains "NSE".

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end.

This token may be unencrypted.



Change payment delay

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CPD".

  • Time seed.

  • Generator application identifier.

  • The account name of the user.

  • Payment delay. If the user didn't specify a payment delay, this field contains "NPD". For security reasons, once the payment delay is set, it can only be increased (not decreased).

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end.

This token may be unencrypted.



Change inheritance trigger timeframe

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CITT".

  • Time seed.

  • Generator application identifier.

  • The account name of the user.

  • Inheritance trigger timeframe.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end.

This token may be unencrypted.



Change show payment history

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "CSPH".

  • Time seed.

  • Generator application identifier.

  • The account name of the user.

  • Show payment history. This is "SH" if the history has to be shown, and "HH" if it has to be hidden.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end.

This token may be unencrypted.



Add inheritor

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "AI".

  • Time seed.

  • The account name of the user.

  • The account name of the recipient of the inheritance.

  • The number of inheritance shares received by the recipient account.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end. Depending on the service, if the token is not encrypted, only the first X bytes (minimum 8) of the hash are used.

This token may be unencrypted.

See Inheritors for details.



Remove inheritor

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "RI".

  • Time seed.

  • The account name of the user.

  • The account name of the recipient of the inheritance.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end. Depending on the service, if the token is not encrypted, only the first X bytes (minimum 8) of the hash are used.

This token may be unencrypted.

See Inheritors for details.



Login account

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "LA".

  • Time seed.

  • The account name of the user.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end. Depending on the service, if the token is not encrypted, only the first X bytes (minimum 8) of the hash are used.

This token may be unencrypted.



Make payment

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "MP".

  • Time seed.

  • The account name of the user.

  • The account name of the recipient of the payment.

  • The account name of the arbiter of the payment. If the user didn't specify an arbiter, this field contains "NA".

  • The name of the currency to be paid.

  • The amount of currency to be paid.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end. Depending on the service, if the token is not encrypted, only the first X bytes (minimum 8) of the hash are used.

This token may be unencrypted.



Setup subscription

Fields:

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Action identifier: "SS".

  • Time seed.

  • The account name of the user.

  • The account name of the recipient of the payment.

  • The name of the currency to be paid.

  • The amount of currency to be paid.

  • The timeframe between two consecutive payments.

  • The number of times to make the payment.

  • The token integrity hash as the textual representation (in base 16) of the SHA256 hash of the token version seed and of all the previous fields (without the token field separators) concatenated with the shared secret at the end. Depending on the service, if the token is not encrypted, only the first X bytes (minimum 8) of the hash are used.

This token may be unencrypted.

See Subscriptions for details.



Encrypted tokens

Tokens may be asymmetrically encrypted with the public RSA key, included in AxiomaticTokenizer, of the service where the token is to be sent. The padding is PKCS#1 v1.5.

Encrypted tokens may be sent through unencrypted communication channels, without revealing their content.

The tokens for creating an account and for changing the account's passphrase are (and must) always be encrypted.

All other tokens may be unencrypted (although they can also be encrypted), and this is preferred for the following reasons:

  • Are shorter, so the user can type them.

  • The user can be sure that the application which generates such tokens hasn't changed the typed data and hid it inside the encrypted envelope.

An encrypted token has the following fields (separated by the token field separator):

  • Token version.

  • Service ID. This allows tokens to be processed automatically.

  • Service public key identifier.

  • Encrypted data.

A service must expect to receive a token either encrypted or unencrypted. A token is encrypted if it has exactly 4 fields; the third field is the service's public key identifier.



Execution proof

Two texts called "execution success proof" and "execution error proof" are associated to all tokens.

They are automatically generated by AxiomaticTokenizer, in a unique way, from all the token fields (which are hashed to generate the token integrity hash), and displayed to the user.

Without the execution success proof, the account creation phase would be exposed to potential MITM (= Man-In-The-Middle) attacks, if the attacker could intercept all the Internet traffic of the user who wants to create an account.

To do this, the attacker would have to intercept the original "Create account" token and not forward it to the service. As such, the service would not have an account with the name specified in the token, and so nobody could make payments to it.

Later, when the user would try to access his account, he would likely do it with an unencrypted token, token which would expose the account's name. At this point the attacker would intercept the user's token and send to the service a (shadow) token in order to create the account with the name specified by the user, but with a shared secret known by the attacker.

From this moment on, the attacker would in fact own the account with that name, without anyone's knowledge. At least until he could no longer replace the user's tokens with his own (shadow) tokens, like when the user would use another computer to connect to the Internet.

To prevent this, the execution success proof is automatically computed for the "Create account" token, and after the account is created it is displayed to the user in the response sent by the service.

Since the "Create account" token is encrypted and only the service can decrypt it, nobody else can compute the execution success proof. So, if the execution success proof received back by the user is the one displayed by AxiomaticTokenizer, the user can be sure that his token was indeed processed by the service, and that the account with the name chosen by him is accessible only with his shared secret.

All the other types of tokens are intrinsically secure against MITM attacks, so for them the execution success proof provides only assurance that the token was executed by the service and it wasn't stopped on its way by an attacker (who then sent back to the user a response that the token was executed by the service).

Similarly, the execution error proof only provides assurance that the service reports that the token was not executed, and that it wasn't stopped on its way by an attacker (who then sent back to the user a response that the token was not executed by the service, although it could have been executed if it were let to reach the service).



Weaknesses



Passphrase strength

The security of all tokens depends on how strong the user's passphrase is and on whether a thief can intercept an unencrypted token.

If the passphrase is weak, like a single word, a thief who can intercept a token can use all the known data to initiate a dictionary attack until he finds that a certain passphrase generates the token.

Due to the fact that AxiomaticTokenizer is written in JavaScript and because iterative hashes written in JavaScript are thousands of times slower than iterative hashes written in native code (C), very few hash iterations are used when the shared secret is generated from the user's passphrase. This makes a dictionary attack much easier.

The best choice here is for the user to use a strong passphrase, as is specified in the documentation of AxiomaticTokenizer, made from a memorized part and a written part. Of course, someone might easily get the written part of the passphrase, but this is virtually impossible to do remotely. The memorized part makes the written part useless on its own.



Database

The service's database is another potential weakness. The service must store the shared secrets as they are given by the users. It's not possible to hash them as passwords are hashed because the shared secret is not sent by the user every time he requests an action to be executed.

This means that a thief who has access to the (decrypted) database can steal all the digital currency from all accounts, but clearly this is the last problem the service has.



Integration tips

Service partners and sponsored entities

The implementation of service partners and sponsored entities must not hamper the distributive capabilities of the database.

For this to happen, the fees for the service partners must not be added to their accounts at the same time the payments are made.

Instead, they must be added to a special table and consolidated only once a day / week, either automatically or manually by the service partners.



User privacy

In order to protect the privacy of the users, the service partners and sponsored entities must not know what users have added them to their accounts, and how much and who do they pay.



Token time

For increased safety, a service should consider invalid a token whose time seed is smaller with more than 7 days than the current (service) time, or bigger with more than 1 minute (just in case the clocks are desynchronized).



Multiple token execution

There is no need to verify the entire history of tokens in order to ensure that a token is executed only one time, so long as the time seed of the token is verified to be bigger (not equal) than the time seed of the last successfully executed token (time seed which is stored for each account).



RsaKeyGen

You can use RsaKeyGen (included in the attached archive) to generate RSA keys and encrypt and decrypt data.

You can also look at the source code to see how to decrypt the encrypted tokens using C#:

RSACryptoServiceProvider rsa = FromRsaKeyParams();

string textToDecrypt = TextToDecryptTextBox.Text;

byte[] data = TextUtil.HexTextToArray( textToDecrypt );
byte[] decrypted = rsa.Decrypt( data, false );

// The (decrypted) token.
TextToEncryptTextBox.Text = Encoding.UTF8.GetString( decrypted );

The FromRsaKeyParams is implemented like this:

private RSACryptoServiceProvider FromRsaKeyParams()
{
        RSAParameters rsap = new RSAParameters();

        rsap.Exponent = TextUtil.HexTextToArray( RsaKeyParamETextBox.Text );
        rsap.Modulus = TextUtil.HexTextToArray( RsaKeyParamMTextBox.Text );
        rsap.D = TextUtil.HexTextToArray( RsaKeyParamDTextBox.Text );
        rsap.DP = TextUtil.HexTextToArray( RsaKeyParamDPTextBox.Text );
        rsap.DQ = TextUtil.HexTextToArray( RsaKeyParamDQTextBox.Text );
        rsap.P = TextUtil.HexTextToArray( RsaKeyParamPTextBox.Text );
        rsap.Q = TextUtil.HexTextToArray( RsaKeyParamQTextBox.Text );
        rsap.InverseQ = TextUtil.HexTextToArray( RsaKeyParamQITextBox.Text );

        RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
        rsa.ImportParameters( rsap );
        
        return rsa;
}



Verify encrypted tokens

If you want to see an unencrypted token which was encrypted by AxiomaticTokenizer, first use the "Generate RSA key" function from RsaKeyGen to generate an RSA key.

Copy the "M" key parameter into AxiomaticTokenizer, as the public key of the service for which you generate the token, for example as the value of the "MetalMoney_RsaPublicKeyM" variable. There is no need to set the "E" key parameter, the default value is the same for both applications.

Generate an encrypted token for the service.

Copy the token, just the token field which contains the encrypted data (= the longest one), and paste it in the "To decrypt" text-box from RsaKeyGen. The white spaces are irrelevant.

Click the "RSA decrypt" button, in RsaKeyGen.

In the "To encrypt" text-box, you can see the unencrypted token.



Token submit form

Services can use the token submit form included in the attached archive, where users can type their generated tokens.

You need to customize it to fit your specific requirements.

Although this form can be made to work offline so that the users could simply type tokens in it, this would mean lost flexibility for service providers.



The source code

While you analyze the code, you may realize that you know or you may see a better way to code a certain feature. But you have to consider that the target platform for running the code is the world of mobile browsers, that is, the application must run on PDAs, and therefore your way of doing things is likely unusable.

Another requirement for the target platform is a touch screen. This requirement affects the design of the user interface such as to make it possible to use the fingers as much as possible.

If AxiomaticTokenizer would be written in a high level language, like C#, not in a scripting language, like JavaScript, the programming mechanisms would be different. In the case of JavaScript, the entire program is contained in a single file in order to make its download easy. Various other programming mechanisms are simplified due to this constrain and due to the fact that JavaScript is not type safe. For example, classes are used on a small scale; of course, the small size of AxiomaticTokenizer makes it easy to use global declarations.



Code comments

All combo-box items must contain a textual value which is neither null nor empty. The display text of each item can't be either null or empty.

The "WipeSensitiveData" function is used to overwrite any sensitive data found in the RAM (as unallocated variables). Basically, a large buffer is allocated (and deallocated) in order to overwrite garbage collected variables.



Browser detection

Detecting the browser on which a JavaScript application runs is one tough cookie. Many Internet browsers want to fool the visited websites into thinking that another kind of browser is requesting the HTML pages.

Here is the code:

// Gets the name of the host application, in uppercase.
function GetHostAppName()
{
        var appName = navigator.appName;
        appName = (appName != null) ? appName.toUpperCase() : "";
        
        var userAgent = navigator.userAgent;
        userAgent = (userAgent != null) ? userAgent.toUpperCase() : "";
        
        if( userAgent.lastIndexOf( "Opera".toUpperCase() ) >= 0 )
        {
                // Check this before InternetExplorer because OperaMobile also contains
                // the string "Internet Explorer".
                
                if( userAgent.lastIndexOf( "PPC".toUpperCase() ) >= 0 )
                        return "OperaMobile".toUpperCase();
                else return "Opera".toUpperCase();
        }
        else if( appName == "Microsoft Internet Explorer".toUpperCase() )
                return "InternetExplorer".toUpperCase();
        else if( appName == "Microsoft IE Mobile".toUpperCase() )
                return "InternetExplorerMobile".toUpperCase();
        else if( userAgent.lastIndexOf( "Safari".toUpperCase() ) >= 0 )
                return "Safari".toUpperCase();
        else if( userAgent.lastIndexOf( "Mozilla".toUpperCase() ) >= 0 )
        {
                // This has to be checked last because many Internet browsers contain it.
                
                return "Mozilla".toUpperCase();
        }
        else return ""; // Unknown host application.
}

Then, we simply need to check the text returned by this function:

function IsBrowserInternetExplorer()
{
        return GetHostAppName() == "InternetExplorer".toUpperCase();
}



Portability

The coding in general, and the user interface in particular, had to be adjusted to provide access to the mobile platforms.

For example, color scheming could be done by dynamically changing the style sheets (using the document.stylesheets array), but this can't be done on mobile browsers. Fortunately, CSS provides a way out: multiple class names for any HTML element, like <input type="submit" class="ButtonStyle ChocolateCream_ButtonStyle"/>.

Implementation subtleties for the HTML and JavaScript hosts make debugging difficult at times. For instance, on Internet Explorer Mobile 6, trying to display or set a display text with a null object causes an exception, but works in the other Internet browsers. Another example is, also on Internet Explorer Mobile 6, that a comma at the end of an array's items generates a null item, but no item in the other browsers.

Interestingly, despite the large size AxiomaticTokenizer, the mobile browsers load it and work well with it (although significantly slower than on the desktop editions of the browsers).

One worry that I had was the speed of the big integer library on mobile devices. Although the performance of RSA encryption isn't anywhere near to that of a desktop browser, it's acceptable. For example, generating an encrypted token on a mobile browser, on a mobile device with a 400 MHz microprocessor, takes about 10 seconds.



Color scheming

The best way to implement color scheming is to do it without changing the colors of each visual HTML element, and also without specifying an array with all the HTML elements which need to have a color scheme (because this would need to be updated as the HTML elements from the page are added or deleted).

Color scheming is implemented using a CSS feature: multiple class names for any HTML element, like <input type="submit" class="ButtonStyle ChocolateCream_ButtonStyle"/>. Basically, the colors have been separated from the rest of the CSS properties, like size or font, in order to allow us to have a single size of font for all color schemes.

From this point on, all we need to do is change the class name of the color scheme, that is, simply replace ChocolateCream_ButtonStyle (which is the default color scheme) with the current color scheme (for example PaleBlue_ButtonStyle), like this:

var colorSchemeName = colorSchemeNameArg.toUpperCase();

var prevColorSchemeName = FindPreviousColorSchemeName( className );

className = className.toUpperCase();

if( (prevColorSchemeName != null) && (prevColorSchemeName != "") )
{
        prevColorSchemeName = prevColorSchemeName.toUpperCase();
        
        // Change the widget's CSS class.
        
        if( className.indexOf( prevColorSchemeName ) >= 0 )
                widget.className = className.replace( prevColorSchemeName, colorSchemeName );
}

To change the color scheme of all HTML elements we need to iterate through all the HTML elements from a page, using the document.all array. For some reason, it's not possible to iterate using foreach and it's not possible to get the number of items from the array, but we can do it with plain indexing and stop when we get a null item:

var i = 0;

while( true )
{
        var widget = document.all[ i ];
        if( widget == null ) return;
        
        // Do stuff.
        
        i++;
}

Note that document.all normally needs a string parameter, which is the ID of the HTML element to access, but as you can see here it can also be used to access an HTML element with the specified index in the array.



Wizard-like user interface

A wizard-like user interface is the easiest for the users to work with. At the same time, it is also the most difficult to develop. Due to the fact that Axiomatictokenizer is specifically designed for mobile devices, not desktop computers, a wizard-like user interface fits best in the small space of the display of such a device.

Since the entire user interface is contained in a single file, all HTML elements would be visible when the application were started, unless they are specifically hidden: <div class="FrameStyle" id="DebugFrameRow" style="display: none;">.

The only HTML elements which must be visible when the application starts are the frame (<div class="FrameStyle" id="ApplicationFrameRow">) and the element which says that JavaScript is not working (<div class="ContentRowStyle CenteredStyle ChocolateCream_ContentStyle" id="NoJavaScriptRow">). The latter HTML element is used to simply inform the user that JavaScript is not working on his computer, and that it is required.

From the moment the application starts, HTML elements are displayed only programmatically, organized on pages. Except for the first page, the welcome page, all other pages are displayed when the user clicks on a button (or otherwise interacts with the HTML elements).

The pages which are part of a wizard which collects the data to be used for generating tokens, display a single editable HTML element in order to guide the user step by step through the process of filling in the data required to generate a token.

Since Axiomatictokenizer is a simple application, only two global buttons are present on a wizard's page, one to move to the next wizard step, and one to abort the current wizard (and go back to the main menu).

A wizard is started by calling a method (StartWizard) which receives as parameters an array which describes the wizard's steps / pages, and a JavaScript function which is executed when the user finishes the wizard (this function usually generates a token and displays it).



Translation

Translation is very useful for a global application, particularly for an application whose target is the masses, not advanced computer users who generally know English.

Because Axiomatictokenizer is a simple application, the translation is entirely done when the application starts or when the user changes the current language, not when a page is displayed.

Before anything, we need to setup the resources which contain the translated texts, in this case the LocalizedTexts array. An element of this array contains an ID (by which the search is done in the array), the language of the display text, what HTML property to set in code during translation (this is used only for the automated translation), the actual translated display text, the formatting data (an array of objects). The position of each formatting data element is identified in the translated texts in the usual C style, with indexed placeholders delimited by "{}".

Just like in the case of color schemes, in order to translate the user interface, we need to iterate through all the HTML elements, using the document.all array. We then change the display text of each element with the translated one. All this is automatically done by the SetLocalizedGui function. Here is how the translation happens when the current language is changed:

var langId = document.all[ "LanguageNameComboBox" ].value;
SetCookie( LangIdCookieName, langId );

SetLocalizedGui( langId );

// Localize the header of the welcome page because its text is dynamically set, and it
// is on the same page where the language is changed.
document.all[ "PageHeaderRow" ].innerHTML = FindCurrentLocalizedText( "Welcome", null );

// Localize the "Choose service name" item because the widget which contains it is
// dynamically filled, and it is on the same page where the language is changed.
UpdateComboBoxByIdItem( "ServiceNameComboBox", GenericItemValue_Choose
        , FindCurrentLocalizedText( "ChooseServiceNameItem", null ) );

// Localize the service actions because the widget which contains them is
// dynamically filled, and it is on the same page where the language is changed.
ShowServiceAction();

However, sometimes it may be necessary to manually set the display text of an HTML element, like when the content of a combo-box is programmatically populated. In such a case, we need to call the FindCurrentLocalizedText function. This will search for a translated text in the LocalizedTexts array, for the current language. This function also accepts formatting data. Here is how the manual translation of an HTML element is done:

document.all[ "PageHeaderRow" ].innerHTML = FindCurrentLocalizedText( "Welcome", null );

Here is how manual translation with formatting data is done:

var extractedChecksum = GetAccountNameChecksum( accountNameArg );
var accountName = BlendAccountName( accountNameArg, serviceNameArg );
var computedChecksum = ComputeAccountNameChecksum( accountName.toUpperCase() );

if( extractedChecksum.toUpperCase() == computedChecksum.toUpperCase() ) return null;
else return FindCurrentLocalizedText( "InvalidAccountNameChecksum"
        , [ extractedChecksum, computedChecksum ] );



Known issues

Opera 9.24 and Opera Mobile 8.65 don't visually update the combo-box items which are automatically selected. Opera 9.5 doesn't have this problem.

Firefox sometimes doesn't activate the function to copy text (from outside a text-box) to clipboard. If this happens, first select some text from a text-box, then select and copy the text of a token.



In order to properly see the integrated keyboard and the "Dice – character mappings" table on InternetExplorer Mobile, the "Menu \ View \ One column" setting must not be set.



Q&A

Can AxiomaticTokenizer be deployed on an existing online payment service?

Yes. It's a generic system. However, this is only the client side, the user interface. An online payment service has to implement the server side, that is, code which parses the incoming tokens and executes the requested actions in the database.



May I put a "Make payment" token in the purchase form of a shopping website?

Yes, if the passphrase of the account from which you pay was chosen as recommended in the documentation of AxiomaticTokenizer.



I have seen some proxy websites which send tokens to the service, to help mitigate DDOS attacks. May I send a token through such a proxy?

Yes, if the passphrase of the account from which you pay was chosen as recommended in the documentation of AxiomaticTokenizer.



I am not sure that my last payment was actually made. Can I generate a new token with the same payment information?

No! Just resend the same token until you receive an execution proof from the service (but don't try too many times because the service doesn't send an execution proof when the time seed of the token is smaller or equal with the time seed of the last successfully executed token).

If you receive the execution error proof, it's guaranteed that the payment was not executed. DO NOT generate another token with the same payment information unless you want to make a new payment.



For some reason, a token which I generated an hour ago didn't reach the service; or it might have, but I am not sure. How can I ensure that it's ignored if it eventually reaches the service?

Generate another token (for example, for login) and send it to the service. If this token reaches the service and it's executed, the older token will not be executed if it reaches the service afterwards.



What information is saved by AxiomaticTokenizer in order to later access an account?

None. AxiomaticTokenizer is stateless, that is, it requires no saved information in order to access an account. The user must remember or store his account names and passphrases.

If a device with AxiomaticTokenizer is lost, all the accounts of its owner can still be accessed with another device.

A user may choose to have various account names saved by AxiomaticTokenizer.



There is absolutely no amount of security (provider-based, user-level hardware, etc...) that can overcome the user's willingness to hand over access to a social engineering con artist.

The purpose of AxiomaticTokenizer is to offer a technological solution to people who want to protect their money inside the money issuer.

What people choose to do with their money is their choice, not for AxiomaticTokenizer to police.



History

01.07.2008 – All tokens have a service ID field to help with automatic processing. The token submit form can now automatically select the processing weblink.

31.05.2008 – The Execution proof is usable for all tokens.

27.03.2008 – Sent the article for publication to CodeProject.



License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

GeorgeHara



Location: Micronesia, Federated States Of Micronesia, Federated States Of

Other popular Cryptography & Security articles:

Article Top
Sign Up to vote for this article
You must